[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