[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [calligra/vector_compositioning_kazakov] /: Added first multi-arch implementation of KisCircleMaskGe
From:       Dmitry Kazakov <dimula73 () gmail ! com>
Date:       2012-12-06 9:52:49
Message-ID: 20121206095249.634C1A60C4 () git ! kde ! org
[Download RAW message or body]

Git commit fe65171646b480563d56d0dfd8a295a3a7523efe by Dmitry Kazakov.
Committed on 06/12/2012 at 09:18.
Pushed by dkazakov into branch 'vector_compositioning_kazakov'.

Added first multi-arch implementation of KisCircleMaskGenerator code

It is not yet finished:
1) It doesn't compile on !HAVE_VC
2) It is not merged with composition factories code

M  +8    -0    CMakeLists.txt
M  +1    -1    krita/benchmarks/kis_mask_generator_benchmark.cpp
M  +4    -1    krita/image/CMakeLists.txt
M  +14   -0    krita/image/kis_base_mask_generator.cpp
M  +4    -3    krita/image/kis_base_mask_generator.h
A  +92   -0    krita/image/kis_brush_mask_applicator_base.h     [License: GPL (v2+)]
A  +118  -0    krita/image/kis_brush_mask_applicator_factories.cpp     [License: GPL \
(v2+)] A  +73   -0    krita/image/kis_brush_mask_applicator_factories.h     [License: \
GPL (v2+)] A  +203  -0    krita/image/kis_brush_mask_applicators.h     [License: GPL \
(v2+)] M  +9    -68   krita/image/kis_circle_mask_generator.cpp
M  +4    -4    krita/image/kis_circle_mask_generator.h
A  +30   -0    krita/image/kis_circle_mask_generator_p.h     [License: GPL (v2+)]
M  +11   -180  krita/plugins/paintops/libbrush/kis_auto_brush.cpp

http://commits.kde.org/calligra/fe65171646b480563d56d0dfd8a295a3a7523efe

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 025510b..92e266f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -379,6 +379,14 @@ if(HAVE_VC)
       endif(PACKAGERS_BUILD)
     endmacro()
 
+    macro(ko_compile_for_all_implementations _objs _src _opts)
+      if(PACKAGERS_BUILD)
+        vc_compile_for_all_implementations(${_objs} ${_src} ${_opts})
+      else(PACKAGERS_BUILD)
+        set(${_objs} ${_src})
+      endif(PACKAGERS_BUILD)
+    endmacro()
+
     if (NOT PACKAGERS_BUILD)
       # Optimize the whole Calligra for current architecture
       set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Vc_DEFINITIONS}")
diff --git a/krita/benchmarks/kis_mask_generator_benchmark.cpp \
b/krita/benchmarks/kis_mask_generator_benchmark.cpp index d861ba7..9ea4db7 100644
--- a/krita/benchmarks/kis_mask_generator_benchmark.cpp
+++ b/krita/benchmarks/kis_mask_generator_benchmark.cpp
@@ -54,7 +54,7 @@ void KisMaskGeneratorBenchmark::benchmarkSIMD()
     QBENCHMARK{
         for(int y = 0; y < 1000; ++y)
         {
-            gen.processRowFast(buffer, width, y, 0.0f, 1.0f, 500.0f, 500.0f, 0.5f, \
0.5f); +//            gen.processRowFast(buffer, width, y, 0.0f, 1.0f, 500.0f, \
500.0f, 0.5f, 0.5f);  }
     }
     Vc::free(buffer);
diff --git a/krita/image/CMakeLists.txt b/krita/image/CMakeLists.txt
index 727b35c..6fcafd6 100644
--- a/krita/image/CMakeLists.txt
+++ b/krita/image/CMakeLists.txt
@@ -54,7 +54,9 @@ include_directories( ${KDE4_INCLUDE_DIR}/threadweaver/
 
 if(HAVE_VC)
   include_directories(${Vc_INCLUDE_DIR})
-#  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Vc_DEFINITIONS}")
+  ko_compile_for_all_implementations(__per_arch_circle_mask_generator_objs \
kis_brush_mask_applicator_factories.cpp "-fPIC") +else(HAVE_VC)
+  set(__per_arch_circle_mask_generator_objs kis_brush_mask_applicator_factories.cpp)
 endif(HAVE_VC)
 
 set(kritaimage_LIB_SRCS
@@ -158,6 +160,7 @@ set(kritaimage_LIB_SRCS
    kis_circle_mask_generator.cpp
    kis_gauss_circle_mask_generator.cpp
    kis_gauss_rect_mask_generator.cpp
+   ${__per_arch_circle_mask_generator_objs}
    kis_gtl_lock.cpp
    kis_curve_circle_mask_generator.cpp
    kis_curve_rect_mask_generator.cpp
diff --git a/krita/image/kis_base_mask_generator.cpp \
b/krita/image/kis_base_mask_generator.cpp index 7c4b4d3..63e9a0a 100644
--- a/krita/image/kis_base_mask_generator.cpp
+++ b/krita/image/kis_base_mask_generator.cpp
@@ -31,6 +31,8 @@
 #include "kis_cubic_curve.h"
 #include "kis_curve_circle_mask_generator.h"
 #include "kis_curve_rect_mask_generator.h"
+#include "kis_brush_mask_applicator_factories.h"
+
 
 KisMaskGenerator::KisMaskGenerator(qreal diameter, qreal ratio, qreal fh, qreal fv, \
int spikes, Type type, const KoID& id) : d(new Private), m_id(id)  {
@@ -42,11 +44,13 @@ KisMaskGenerator::KisMaskGenerator(qreal diameter, qreal ratio, \
qreal fh, qreal  d->spikes = spikes;
     d->cachedSpikesAngle = M_PI / d->spikes;
     d->type = type;
+    d->defaultMaskProcessor = 0;
     init();
 }
 
 KisMaskGenerator::~KisMaskGenerator()
 {
+    delete d->defaultMaskProcessor;
     delete d;
 }
 
@@ -67,6 +71,16 @@ bool KisMaskGenerator::shouldVectorize() const
     return false;
 }
 
+KisBrushMaskApplicatorBase* KisMaskGenerator::applicator()
+{
+    if (!d->defaultMaskProcessor) {
+        d->defaultMaskProcessor =
+            createOptimizedClass<MaskApplicatorFactory<KisMaskGenerator, \
KisBrushMaskScalarApplicator> >(this); +    }
+
+    return d->defaultMaskProcessor;
+}
+
 void KisMaskGenerator::toXML(QDomDocument& doc, QDomElement& e) const
 {
     Q_UNUSED(doc);
diff --git a/krita/image/kis_base_mask_generator.h \
b/krita/image/kis_base_mask_generator.h index 15efaa6..62dde87 100644
--- a/krita/image/kis_base_mask_generator.h
+++ b/krita/image/kis_base_mask_generator.h
@@ -24,6 +24,7 @@
 #include <klocale.h>
 
 #include "krita_export.h"
+#include "kis_brush_mask_applicator_base.h"
 
 class QDomElement;
 class QDomDocument;
@@ -68,13 +69,12 @@ public:
      */
     virtual quint8 valueAt(qreal x, qreal y) const = 0;
 
-    virtual void processRowFast(float* /*buffer*/, int /*width*/, float /*y*/, float \
                /*cosa*/, float /*sina*/,
-                                float /*centerX*/, float /*centerY*/, float \
                /*invScaleX*/, float /*invScaleY*/) {}
-
     virtual bool shouldSupersample() const;
 
     virtual bool shouldVectorize() const;
 
+    virtual KisBrushMaskApplicatorBase* applicator();
+
     virtual void toXML(QDomDocument& , QDomElement&) const;
 
     /**
@@ -115,6 +115,7 @@ protected:
         bool empty;
         Type type;
         QString curveString;
+        KisBrushMaskApplicatorBase *defaultMaskProcessor;
     };
 
     Private* const d;
diff --git a/krita/image/kis_brush_mask_applicator_base.h \
b/krita/image/kis_brush_mask_applicator_base.h new file mode 100644
index 0000000..ea29583
--- /dev/null
+++ b/krita/image/kis_brush_mask_applicator_base.h
@@ -0,0 +1,92 @@
+/*
+ *  Copyright (c) 2012 Dmitry Kazakov <dimula73@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_BRUSH_MASK_APPLICATOR_BASE_H
+#define __KIS_BRUSH_MASK_APPLICATOR_BASE_H
+
+#include "kis_types.h"
+#include "kis_fixed_paint_device.h"
+#include "math.h"
+
+
+struct MaskProcessingData {
+    MaskProcessingData(KisFixedPaintDeviceSP _device,
+                       const KoColorSpace* _colorSpace,
+                       qreal _randomness,
+                       qreal _density,
+                       double _centerX,
+                       double _centerY,
+                       double _invScaleX,
+                       double _invScaleY,
+                       double _angle)
+        {
+            device = _device;
+            colorSpace = _colorSpace;
+            randomness = _randomness;
+            density = _density;
+            centerX = _centerX;
+            centerY = _centerY;
+            invScaleX = _invScaleX;
+            invScaleY = _invScaleY;
+            cosa = cos(_angle);
+            sina = sin(_angle);
+            pixelSize = colorSpace->pixelSize();
+        }
+
+
+
+    KisFixedPaintDeviceSP device;
+    const KoColorSpace* colorSpace;
+    qreal randomness;
+    qreal density;
+    double centerX;
+    double centerY;
+    double invScaleX;
+    double invScaleY;
+
+    double cosa;
+    double sina;
+
+    qint32 pixelSize;
+};
+
+struct KisBrushMaskApplicatorBase
+{
+    virtual ~KisBrushMaskApplicatorBase() {}
+    virtual void process(const QRect &rect) = 0;
+
+    inline void initializeData(const MaskProcessingData *data) {
+        m_d = data;
+    }
+
+protected:
+    const MaskProcessingData *m_d;
+};
+
+struct OperatorWrapper {
+    OperatorWrapper(KisBrushMaskApplicatorBase *applicator)
+        : m_applicator(applicator) {}
+
+    inline void operator() (const QRect& rect) {
+        m_applicator->process(rect);
+    }
+
+    KisBrushMaskApplicatorBase *m_applicator;
+};
+
+#endif /* __KIS_BRUSH_MASK_APPLICATOR_BASE_H */
diff --git a/krita/image/kis_brush_mask_applicator_factories.cpp \
b/krita/image/kis_brush_mask_applicator_factories.cpp new file mode 100644
index 0000000..e20086a
--- /dev/null
+++ b/krita/image/kis_brush_mask_applicator_factories.cpp
@@ -0,0 +1,118 @@
+/*
+ *  Copyright (c) 2012 Dmitry Kazakov <dimula73@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_brush_mask_applicator_factories.h"
+
+#include "kis_circle_mask_generator.h"
+#include "kis_circle_mask_generator_p.h"
+#include "kis_brush_mask_applicators.h"
+
+
+#define a(_s) #_s
+#define b(_s) a(_s)
+
+template<>
+template<>
+MaskApplicatorFactory<KisMaskGenerator, KisBrushMaskScalarApplicator>::ReturnType
+MaskApplicatorFactory<KisMaskGenerator, \
KisBrushMaskScalarApplicator>::create<VC_IMPL>(ParamType maskGenerator) +{
+    qDebug() << "Creating scalar applicator" << b(VC_IMPL);
+    return new KisBrushMaskScalarApplicator<KisMaskGenerator,VC_IMPL>(maskGenerator);
 +}
+
+struct KisCircleMaskGenerator::FastRowProcessor
+{
+    FastRowProcessor(KisCircleMaskGenerator *maskGenerator)
+        : d(maskGenerator->d) {}
+
+    template<Vc::Implementation _impl>
+    void process(float* buffer, int width, float y, float cosa, float sina,
+                 float centerX, float centerY, float invScaleX, float invScaleY);
+
+    KisCircleMaskGenerator::Private *d;
+};
+
+template<>
+template<>
+MaskApplicatorFactory<KisCircleMaskGenerator, \
KisBrushMaskVectorApplicator>::ReturnType \
+MaskApplicatorFactory<KisCircleMaskGenerator, \
KisBrushMaskVectorApplicator>::create<VC_IMPL>(ParamType maskGenerator) +{
+    qDebug() << "Creating vector applicator" << b(VC_IMPL);
+    return new KisBrushMaskVectorApplicator<KisCircleMaskGenerator,VC_IMPL>(maskGenerator);
 +}
+
+template<> void KisCircleMaskGenerator::
+FastRowProcessor::process<VC_IMPL>(float* buffer, int width, float y, float cosa, \
float sina, +                                   float centerX, float centerY, float \
invScaleX, float invScaleY) +{
+    float y_ = (y - centerY) * invScaleY;
+    float sinay_ = sina * y_;
+    float cosay_ = cosa * y_;
+
+    float *initValues = Vc::malloc<float, Vc::AlignOnVector>(Vc::float_v::Size);
+    for(int i = 0; i < Vc::float_v::Size; i++) {
+        initValues[i] = (float)i;
+    }
+
+    float* bufferPointer = buffer;
+
+    Vc::float_v currentIndices(initValues);
+
+    Vc::float_v increment((float)Vc::float_v::Size);
+    Vc::float_v vCenterX(centerX);
+    Vc::float_v vInvScaleX(invScaleX);
+
+    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);
+
+    for (int i=0; i < width; i+= Vc::float_v::Size){
+
+        Vc::float_v x_ = (currentIndices - vCenterX) * vInvScaleX;
+
+        Vc::float_v xr = x_ * vCosa - vSinaY_;
+        Vc::float_v yr = x_ * vSina + vCosaY_;
+
+        Vc::float_v n = ((xr * vXCoeff) * (xr * vXCoeff)) + ((yr * vYCoeff) * (yr * \
vYCoeff)); +
+        Vc::float_v vNormFade =((xr * vTransformedFadeX) * (xr * vTransformedFadeX)) \
+ ((yr * vTransformedFadeY) * (yr * vTransformedFadeY)); +
+        //255 * n * (normeFade - 1) / (normeFade - n)
+        Vc::float_v vFade = n * (vNormFade - vOne) / (vNormFade - n);
+        // Mask out the inner circe of the mask
+        Vc::float_m mask = vNormFade < vOne;
+        vFade.setZero(mask);
+        vFade = Vc::min(vFade, vOne);
+
+        vFade.store(bufferPointer);
+        currentIndices = currentIndices + increment;
+
+        bufferPointer += Vc::float_v::Size;
+    }
+
+    Vc::free<float>(initValues);
+}
diff --git a/krita/image/kis_brush_mask_applicator_factories.h \
b/krita/image/kis_brush_mask_applicator_factories.h new file mode 100644
index 0000000..8430d82
--- /dev/null
+++ b/krita/image/kis_brush_mask_applicator_factories.h
@@ -0,0 +1,73 @@
+/*
+ *  Copyright (c) 2012 Dmitry Kazakov <dimula73@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_CIRCLE_MASK_APPLICATOR_FACTORY_H
+#define __KIS_CIRCLE_MASK_APPLICATOR_FACTORY_H
+
+#include "kis_brush_mask_applicator_base.h"
+
+#include <Vc/Vc>
+#include <Vc/common/support.h>
+
+template<class MaskGenerator, Vc::Implementation _impl>
+struct KisBrushMaskScalarApplicator;
+
+template<class MaskGenerator, Vc::Implementation _impl>
+struct KisBrushMaskVectorApplicator;
+
+
+template<class MaskGenerator,
+         template<class U, Vc::Implementation V> class Applicator>
+struct MaskApplicatorFactory
+{
+    typedef MaskGenerator* ParamType;
+    typedef KisBrushMaskApplicatorBase* ReturnType;
+
+    template<Vc::Implementation _impl>
+    static ReturnType create(ParamType maskGenerator);
+};
+
+template<class FactoryType>
+typename FactoryType::ReturnType
+createOptimizedClass(typename FactoryType::ParamType param)
+{
+    /*if (Vc::isImplementationSupported(Vc::Fma4Impl)) {
+        return FactoryType::template create<Vc::Fma4Impl>(param);
+    } else if (Vc::isImplementationSupported(Vc::XopImpl)) {
+        return FactoryType::template create<Vc::XopImpl>(param);
+        } else*/
+    if (Vc::isImplementationSupported(Vc::AVXImpl)) {
+        return FactoryType::template create<Vc::AVXImpl>(param);
+    } else if (Vc::isImplementationSupported(Vc::SSE42Impl)) {
+        return FactoryType::template create<Vc::SSE42Impl>(param);
+    } else if (Vc::isImplementationSupported(Vc::SSE41Impl)) {
+        return FactoryType::template create<Vc::SSE41Impl>(param);
+    } else if (Vc::isImplementationSupported(Vc::SSE4aImpl)) {
+        return FactoryType::template create<Vc::SSE4aImpl>(param);
+    } else if (Vc::isImplementationSupported(Vc::SSSE3Impl)) {
+        return FactoryType::template create<Vc::SSSE3Impl>(param);
+    } else if (Vc::isImplementationSupported(Vc::SSE3Impl)) {
+        return FactoryType::template create<Vc::SSE3Impl>(param);
+    } else if (Vc::isImplementationSupported(Vc::SSE2Impl)) {
+        return FactoryType::template create<Vc::SSE2Impl>(param);
+    } else {
+        return FactoryType::template create<Vc::ScalarImpl>(param);
+    }
+}
+
+#endif /* __KIS_CIRCLE_MASK_APPLICATOR_FACTORY_H */
diff --git a/krita/image/kis_brush_mask_applicators.h \
b/krita/image/kis_brush_mask_applicators.h new file mode 100644
index 0000000..277964d
--- /dev/null
+++ b/krita/image/kis_brush_mask_applicators.h
@@ -0,0 +1,203 @@
+/*
+ *  Copyright (c) 2012 Sven Langkamp  <sven.langkamp@gmail.com>
+ *  Copyright (c) 2012 Dmitry Kazakov <dimula73@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_BRUSH_MASK_APPLICATORS_H
+#define __KIS_BRUSH_MASK_APPLICATORS_H
+
+#include "kis_brush_mask_applicator_base.h"
+
+// 3x3 supersampling
+#define SUPERSAMPLING 3
+
+#if defined(_WIN32) || defined(_WIN64)
+#include <stdlib.h>
+#define srand48 srand
+inline double drand48() {
+    return double(rand()) / RAND_MAX;
+}
+#endif
+
+
+template<class MaskGenerator, Vc::Implementation _impl>
+struct KisBrushMaskScalarApplicator : public KisBrushMaskApplicatorBase
+{
+    KisBrushMaskScalarApplicator(MaskGenerator *maskGenerator)
+        : m_maskGenerator(maskGenerator)
+    {
+    }
+
+    void process(const QRect &rect) {
+        processScalar(rect);
+    }
+
+protected:
+    void processScalar(const QRect &rect);
+
+protected:
+    MaskGenerator *m_maskGenerator;
+};
+
+template<class MaskGenerator, Vc::Implementation _impl>
+struct KisBrushMaskVectorApplicator : public \
KisBrushMaskScalarApplicator<MaskGenerator, _impl> +{
+    KisBrushMaskVectorApplicator(MaskGenerator *maskGenerator)
+        : KisBrushMaskScalarApplicator<MaskGenerator, _impl>(maskGenerator)
+    {
+    }
+
+    void process(const QRect &rect) {
+        startProcessing(rect, TypeHelper<MaskGenerator, _impl>());
+    }
+
+protected:
+    void processVector(const QRect &rect);
+
+private:
+    template<class U, Vc::Implementation V> struct TypeHelper {};
+
+private:
+    template<class U>
+    inline void startProcessing(const QRect &rect, TypeHelper<U, Vc::ScalarImpl>) {
+        KisBrushMaskScalarApplicator<MaskGenerator, _impl>::processScalar(rect);
+    }
+
+    template<class U, Vc::Implementation V>
+    inline void startProcessing(const QRect &rect, TypeHelper<U, V>) {
+        MaskGenerator *m_maskGenerator = KisBrushMaskScalarApplicator<MaskGenerator, \
_impl>::m_maskGenerator; +
+        if (m_maskGenerator->shouldVectorize()) {
+            processVector(rect);
+        } else {
+            KisBrushMaskScalarApplicator<MaskGenerator, _impl>::processScalar(rect);
+        }
+    }
+};
+
+template<class MaskGenerator, Vc::Implementation _impl>
+void KisBrushMaskVectorApplicator<MaskGenerator, _impl>::processVector(const QRect \
&rect) +{
+    const MaskProcessingData *m_d = KisBrushMaskApplicatorBase::m_d;
+    MaskGenerator *m_maskGenerator = KisBrushMaskScalarApplicator<MaskGenerator, \
_impl>::m_maskGenerator; +
+    qreal random = 1.0;
+    quint8* dabPointer = m_d->device->data() + rect.y() * rect.width() * \
m_d->pixelSize; +    quint8 alphaValue = OPACITY_TRANSPARENT_U8;
+    // this offset is needed when brush size is smaller then fixed device size
+    int offset = (m_d->device->bounds().width() - rect.width()) * m_d->pixelSize;
+
+    int width = rect.width();
+
+    // We need to calculate with a multiple of the width of the simd register
+    int alignOffset = 0;
+    if (width % Vc::float_v::Size != 0) {
+        alignOffset = Vc::float_v::Size - (width % Vc::float_v::Size);
+    }
+    int simdWidth = width + alignOffset;
+
+    float *buffer = Vc::malloc<float, Vc::AlignOnVector>(simdWidth);
+
+    typename MaskGenerator::FastRowProcessor processor(m_maskGenerator);
+
+    for (int y = rect.y(); y < rect.y() + rect.height(); y++) {
+
+        processor.template process<_impl>(buffer, simdWidth, y, m_d->cosa, \
m_d->sina, m_d->centerX, m_d->centerY, m_d->invScaleX, m_d->invScaleY); +
+        if (m_d->randomness != 0.0 || m_d->density != 1.0) {
+            for (int x = 0; x < width; x++) {
+
+                if (m_d->randomness!= 0.0){
+                    random = (1.0 - m_d->randomness) + m_d->randomness * \
float(rand()) / RAND_MAX; +                }
+
+                alphaValue = quint8( (OPACITY_OPAQUE_U8 - buffer[x]*255) * random);
+
+                // avoid computation of random numbers if density is full
+                if (m_d->density != 1.0){
+                    // compute density only for visible pixels of the mask
+                    if (alphaValue != OPACITY_TRANSPARENT_U8){
+                        if ( !(m_d->density >= drand48()) ){
+                            alphaValue = OPACITY_TRANSPARENT_U8;
+                        }
+                    }
+                }
+
+                m_d->colorSpace->applyAlphaU8Mask(dabPointer, &alphaValue, 1);
+                dabPointer += m_d->pixelSize;
+            }
+        } else {
+            m_d->colorSpace->applyInverseNormedFloatMask(dabPointer, buffer, width);
+            dabPointer += width * m_d->pixelSize;
+        }//endfor x
+        dabPointer += offset;
+    }//endfor y
+    Vc::free(buffer);
+}
+
+template<class MaskGenerator, Vc::Implementation _impl>
+void KisBrushMaskScalarApplicator<MaskGenerator, _impl>::processScalar(const QRect \
&rect) +{
+    const MaskProcessingData *m_d = KisBrushMaskApplicatorBase::m_d;
+    MaskGenerator *m_maskGenerator = KisBrushMaskScalarApplicator<MaskGenerator, \
_impl>::m_maskGenerator; +
+    qreal random = 1.0;
+    quint8* dabPointer = m_d->device->data() + rect.y() * rect.width() * \
m_d->pixelSize; +    quint8 alphaValue = OPACITY_TRANSPARENT_U8;
+    // this offset is needed when brush size is smaller then fixed device size
+    int offset = (m_d->device->bounds().width() - rect.width()) * m_d->pixelSize;
+    int supersample = (m_maskGenerator->shouldSupersample() ? SUPERSAMPLING : 1);
+    double invss = 1.0 / supersample;
+    int samplearea = supersample * supersample;
+    for (int y = rect.y(); y < rect.y() + rect.height(); y++) {
+        for (int x = rect.x(); x < rect.x() + rect.width(); x++) {
+            int value = 0;
+            for (int sy = 0; sy < supersample; sy++) {
+                for (int sx = 0; sx < supersample; sx++) {
+                    double x_ = (x + sx * invss - m_d->centerX) * m_d->invScaleX;
+                    double y_ = (y + sy * invss - m_d->centerY) * m_d->invScaleY;
+                    double maskX = m_d->cosa * x_ - m_d->sina * y_;
+                    double maskY = m_d->sina * x_ + m_d->cosa * y_;
+                    value += m_maskGenerator->valueAt(maskX, maskY);
+                }
+            }
+            if (supersample != 1) value /= samplearea;
+
+            if (m_d->randomness!= 0.0){
+                random = (1.0 - m_d->randomness) + m_d->randomness * float(rand()) / \
RAND_MAX; +            }
+
+            alphaValue = quint8( (OPACITY_OPAQUE_U8 - value) * random);
+
+            // avoid computation of random numbers if density is full
+            if (m_d->density != 1.0){
+                // compute density only for visible pixels of the mask
+                if (alphaValue != OPACITY_TRANSPARENT_U8){
+                    if ( !(m_d->density >= drand48()) ){
+                        alphaValue = OPACITY_TRANSPARENT_U8;
+                    }
+                }
+            }
+
+            m_d->colorSpace->applyAlphaU8Mask(dabPointer, &alphaValue, 1);
+            dabPointer += m_d->pixelSize;
+        }//endfor x
+        dabPointer += offset;
+    }//endfor y
+}
+
+#endif /* __KIS_BRUSH_MASK_APPLICATORS_H */
diff --git a/krita/image/kis_circle_mask_generator.cpp \
b/krita/image/kis_circle_mask_generator.cpp index 6e84219..5fbefb4 100644
--- a/krita/image/kis_circle_mask_generator.cpp
+++ b/krita/image/kis_circle_mask_generator.cpp
@@ -30,13 +30,10 @@
 
 #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"
 
-struct KisCircleMaskGenerator::Private {
-    double xcoef, ycoef;
-    double xfadecoef, yfadecoef;
-    double transformedFadeX, transformedFadeY;
-};
 
 KisCircleMaskGenerator::KisCircleMaskGenerator(qreal diameter, qreal ratio, qreal \
                fh, qreal fv, int spikes)
         : KisMaskGenerator(diameter, ratio, fh, fv, spikes, CIRCLE, DefaultId), \
d(new Private) @@ -47,10 +44,13 @@ \
                KisCircleMaskGenerator::KisCircleMaskGenerator(qreal diameter, qreal \
                ratio, qrea
     d->yfadecoef = (KisMaskGenerator::d->fv == 0) ? 1 : (1.0 / \
(KisMaskGenerator::d->fv * KisMaskGenerator::d->ratio * width()));  \
d->transformedFadeX = d->xfadecoef * softness();  d->transformedFadeY = d->yfadecoef \
* softness(); +
+    d->applicator = \
createOptimizedClass<MaskApplicatorFactory<KisCircleMaskGenerator, \
KisBrushMaskVectorApplicator> >(this);  }
 
 KisCircleMaskGenerator::~KisCircleMaskGenerator()
 {
+    delete d->applicator;
     delete d;
 }
 
@@ -64,6 +64,10 @@ bool KisCircleMaskGenerator::shouldVectorize() const
     return !shouldSupersample() && spikes() == 2;
 }
 
+KisBrushMaskApplicatorBase* KisCircleMaskGenerator::applicator()
+{
+    return d->applicator;
+}
 
 quint8 KisCircleMaskGenerator::valueAt(qreal x, qreal y) const
 {
@@ -117,69 +121,6 @@ quint8 KisCircleMaskGenerator::valueAt(qreal x, qreal y) const
     }
 }
 
-void KisCircleMaskGenerator::processRowFast(float* buffer, int width, float y, float \
                cosa, float sina,
-                                            float centerX, float centerY, float \
                invScaleX, float invScaleY)
-{
-#ifdef HAVE_VC
-    float y_ = (y - centerY) * invScaleY;
-    float sinay_ = sina * y_;
-    float cosay_ = cosa * y_;
-
-    float *initValues = Vc::malloc<float, Vc::AlignOnVector>(Vc::float_v::Size);
-    for(int i = 0; i < Vc::float_v::Size; i++) {
-        initValues[i] = (float)i;
-    }
-
-    float* bufferPointer = buffer;
-
-    Vc::float_v currentIndices(initValues);
-
-    Vc::float_v increment((float)Vc::float_v::Size);
-    Vc::float_v vCenterX(centerX);
-    Vc::float_v vInvScaleX(invScaleX);
-
-    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);
-
-    for (int i=0; i < width; i+= Vc::float_v::Size){
-
-        Vc::float_v x_ = (currentIndices - vCenterX) * vInvScaleX;
-
-        Vc::float_v xr = x_ * vCosa - vSinaY_;
-        Vc::float_v yr = x_ * vSina + vCosaY_;
-
-        Vc::float_v n = ((xr * vXCoeff) * (xr * vXCoeff)) + ((yr * vYCoeff) * (yr * \
                vYCoeff));
-
-        Vc::float_v vNormFade =((xr * vTransformedFadeX) * (xr * vTransformedFadeX)) \
                + ((yr * vTransformedFadeY) * (yr * vTransformedFadeY));
-
-        //255 * n * (normeFade - 1) / (normeFade - n)
-        Vc::float_v vFade = n * (vNormFade - vOne) / (vNormFade - n);
-        // Mask out the inner circe of the mask
-        Vc::float_m mask = vNormFade < vOne;
-        vFade.setZero(mask);
-        vFade = Vc::min(vFade, vOne);
-
-        vFade.store(bufferPointer);
-        currentIndices = currentIndices + increment;
-
-        bufferPointer += Vc::float_v::Size;
-    }
-
-    Vc::free<float>(initValues);
-#endif
-}
-
-
 void KisCircleMaskGenerator::toXML(QDomDocument& d, QDomElement& e) const
 {
     KisMaskGenerator::toXML(d, e);
diff --git a/krita/image/kis_circle_mask_generator.h \
b/krita/image/kis_circle_mask_generator.h index 53b6c61..7cc6416 100644
--- a/krita/image/kis_circle_mask_generator.h
+++ b/krita/image/kis_circle_mask_generator.h
@@ -31,20 +31,20 @@ class QDomDocument;
  */
 class KRITAIMAGE_EXPORT KisCircleMaskGenerator : public KisMaskGenerator
 {
-
+public:
+    struct FastRowProcessor;
 public:
     KisCircleMaskGenerator(qreal radius, qreal ratio, qreal fh, qreal fv, int \
spikes);  virtual ~KisCircleMaskGenerator();
     
     virtual quint8 valueAt(qreal x, qreal y) const;
 
-    virtual void processRowFast(float* buffer, int width, float y, float cosa, float \
                sina,
-                             float centerX, float centerY, float invScaleX, float \
                invScaleY);
-
     virtual bool shouldSupersample() const;
 
     virtual bool shouldVectorize() const;
 
+    KisBrushMaskApplicatorBase* applicator();
+
     virtual void toXML(QDomDocument& , QDomElement&) const;
     
     virtual void setSoftness(qreal softness);
diff --git a/krita/image/kis_circle_mask_generator_p.h \
b/krita/image/kis_circle_mask_generator_p.h new file mode 100644
index 0000000..9cb9449
--- /dev/null
+++ b/krita/image/kis_circle_mask_generator_p.h
@@ -0,0 +1,30 @@
+/*
+ *  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_CIRCLE_MASK_GENERATOR_P_H_
+#define _KIS_CIRCLE_MASK_GENERATOR_P_H_
+
+struct KisCircleMaskGenerator::Private {
+    double xcoef, ycoef;
+    double xfadecoef, yfadecoef;
+    double transformedFadeX, transformedFadeY;
+
+    KisBrushMaskApplicatorBase *applicator;
+};
+
+#endif /* _KIS_CIRCLE_MASK_GENERATOR_P_H_ */
diff --git a/krita/plugins/paintops/libbrush/kis_auto_brush.cpp \
b/krita/plugins/paintops/libbrush/kis_auto_brush.cpp index f7bf3f8..5b4de4c 100644
--- a/krita/plugins/paintops/libbrush/kis_auto_brush.cpp
+++ b/krita/plugins/paintops/libbrush/kis_auto_brush.cpp
@@ -18,14 +18,6 @@
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
-#if defined(_WIN32) || defined(_WIN64)
-#include <stdlib.h>
-#define srand48 srand
-inline double drand48() {
-    return double(rand()) / RAND_MAX;
-}
-#endif
-
 #include "kis_auto_brush.h"
 
 #include <kis_debug.h>
@@ -46,177 +38,8 @@ inline double drand48() {
 #include "kis_mask_generator.h"
 #include "kis_boundary.h"
 
-#include "config-vc.h"
-#ifdef HAVE_VC
-#include <Vc/Vc>
-#include <Vc/IO>
-#include <Vc/common/support.h>
-#endif
-
-// 3x3 supersampling
-#define SUPERSAMPLING 3
-
-struct MaskProcessor
-{
-    MaskProcessor(KisFixedPaintDeviceSP device, const KoColorSpace* cs, qreal \
                randomness, qreal density,
-           double centerX, double centerY, double invScaleX, double invScaleY, \
                double angle,
-           KisMaskGenerator* shape)
-    : m_device(device)
-    , m_cs(cs)
-    , m_randomness(randomness)
-    , m_density(density)
-    , m_pixelSize(cs->pixelSize())
-    , m_centerX(centerX)
-    , m_centerY(centerY)
-    , m_invScaleX(invScaleX)
-    , m_invScaleY(invScaleY)
-    , m_shape(shape)
-    {
-
-        m_cosa = cos(angle);
-        m_sina = sin(angle);
-
-#ifdef HAVE_VC
-        m_canVectorize = Vc::currentImplementationSupported();
-#else
-        m_canVectorize = false;
-#endif
-
-    }
-
-    void operator()(QRect& rect)
-    {
-        process(rect);
-    }
-
-    void process(QRect& rect){
-#ifdef HAVE_VC
-        if (m_canVectorize && m_shape->shouldVectorize()) {
-            processParallel(rect);
-        } else {
-            processScalar(rect);
-        }
-
-#else
-        processScalar(rect);
-#endif
-    }
-
-    void processScalar(QRect& rect){
-        qreal random = 1.0;
-        quint8* dabPointer = m_device->data() + rect.y() * rect.width() * \
                m_pixelSize;
-        quint8 alphaValue = OPACITY_TRANSPARENT_U8;
-        // this offset is needed when brush size is smaller then fixed device size
-        int offset = (m_device->bounds().width() - rect.width()) * m_pixelSize;
-        int supersample = (m_shape->shouldSupersample() ? SUPERSAMPLING : 1);
-        double invss = 1.0 / supersample;
-        int samplearea = supersample * supersample;
-        for (int y = rect.y(); y < rect.y() + rect.height(); y++) {
-            for (int x = rect.x(); x < rect.x() + rect.width(); x++) {
-                int value = 0;
-                for (int sy = 0; sy < supersample; sy++) {
-                    for (int sx = 0; sx < supersample; sx++) {
-                        double x_ = (x + sx * invss - m_centerX) * m_invScaleX;
-                        double y_ = (y + sy * invss - m_centerY) * m_invScaleY;
-                        double maskX = m_cosa * x_ - m_sina * y_;
-                        double maskY = m_sina * x_ + m_cosa * y_;
-                        value += m_shape->valueAt(maskX, maskY);
-                    }
-                }
-                if (supersample != 1) value /= samplearea;
-
-                if (m_randomness!= 0.0){
-                    random = (1.0 - m_randomness) + m_randomness * float(rand()) / \
                RAND_MAX;
-                }
-
-                alphaValue = quint8( (OPACITY_OPAQUE_U8 - value) * random);
 
-                // avoid computation of random numbers if density is full
-                if (m_density != 1.0){
-                    // compute density only for visible pixels of the mask
-                    if (alphaValue != OPACITY_TRANSPARENT_U8){
-                        if ( !(m_density >= drand48()) ){
-                            alphaValue = OPACITY_TRANSPARENT_U8;
-                        }
-                    }
-                }
-
-                m_cs->applyAlphaU8Mask(dabPointer, &alphaValue, 1);
-                dabPointer += m_pixelSize;
-            }//endfor x
-            dabPointer += offset;
-        }//endfor y
-    }
-
-#ifdef HAVE_VC
-    void processParallel(QRect& rect){
-        qreal random = 1.0;
-        quint8* dabPointer = m_device->data() + rect.y() * rect.width() * \
                m_pixelSize;
-        quint8 alphaValue = OPACITY_TRANSPARENT_U8;
-        // this offset is needed when brush size is smaller then fixed device size
-        int offset = (m_device->bounds().width() - rect.width()) * m_pixelSize;
-
-        int width = rect.width();
-
-        // We need to calculate with a multiple of the width of the simd register
-        int alignOffset = 0;
-        if (width % Vc::float_v::Size != 0) {
-            alignOffset = Vc::float_v::Size - (width % Vc::float_v::Size);
-        }
-        int simdWidth = width + alignOffset;
-
-        float *buffer = Vc::malloc<float, Vc::AlignOnVector>(simdWidth);
-
-        for (int y = rect.y(); y < rect.y() + rect.height(); y++) {
-
-            m_shape->processRowFast(buffer, simdWidth, y, m_cosa, m_sina, m_centerX, \
m_centerY, m_invScaleX, m_invScaleY);  
-            if (m_randomness != 0.0 || m_density != 1.0) {
-                for (int x = 0; x < width; x++) {
-
-                    if (m_randomness!= 0.0){
-                        random = (1.0 - m_randomness) + m_randomness * float(rand()) \
                / RAND_MAX;
-                    }
-
-                    alphaValue = quint8( (OPACITY_OPAQUE_U8 - buffer[x]*255) * \
                random);
-
-                    // avoid computation of random numbers if density is full
-                    if (m_density != 1.0){
-                        // compute density only for visible pixels of the mask
-                        if (alphaValue != OPACITY_TRANSPARENT_U8){
-                            if ( !(m_density >= drand48()) ){
-                                alphaValue = OPACITY_TRANSPARENT_U8;
-                            }
-                        }
-                    }
-
-                    m_cs->applyAlphaU8Mask(dabPointer, &alphaValue, 1);
-                    dabPointer += m_pixelSize;
-                }
-            } else {
-                m_cs->applyInverseNormedFloatMask(dabPointer, buffer, width);
-                dabPointer += width*m_pixelSize;
-            }//endfor x
-            dabPointer += offset;
-        }//endfor y
-        Vc::free(buffer);
-    }
-#endif
-
-    KisFixedPaintDeviceSP m_device;
-    const KoColorSpace* m_cs;
-    qreal m_randomness;
-    qreal m_density;
-    quint32 m_pixelSize;
-    double m_centerX;
-    double m_centerY;
-    double m_invScaleX;
-    double m_invScaleY;
-    double m_cosa;
-    double m_sina;
-    KisMaskGenerator* m_shape;
-    bool m_canVectorize;
-};
 
 struct KisAutoBrush::Private {
     KisMaskGenerator* shape;
@@ -405,7 +228,14 @@ void \
KisAutoBrush::generateMaskAndApplyMaskOrCreateDab(KisFixedPaintDeviceSP dst  }
     }
 
-    MaskProcessor s(dst, cs, d->randomness, d->density, centerX, centerY, invScaleX, \
invScaleY, angle, d->shape); +    MaskProcessingData data(dst, cs, d->randomness, \
d->density, +                            centerX, centerY,
+                            invScaleX, invScaleY,
+                            angle);
+
+    KisBrushMaskApplicatorBase *applicator = d->shape->applicator();
+    applicator->initializeData(&data);
+
     int jobs = d->idealThreadCountCached;
     if(dstHeight > 100 && jobs >= 4) {
         int splitter = dstHeight/jobs;
@@ -414,10 +244,11 @@ void \
KisAutoBrush::generateMaskAndApplyMaskOrCreateDab(KisFixedPaintDeviceSP dst  rects << \
QRect(0, i*splitter, dstWidth, splitter);  }
         rects << QRect(0, (jobs - 1)*splitter, dstWidth, dstHeight - (jobs - \
                1)*splitter);
-        QtConcurrent::blockingMap(rects, s);
+        OperatorWrapper wrapper(applicator);
+        QtConcurrent::blockingMap(rects, wrapper);
     } else {
         QRect rect(0, 0, dstWidth, dstHeight);
-        s.process(rect);
+        applicator->process(rect);
     }
 }
 


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic