Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_brush_mask_vector_applicator.h
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2012 Sven Langkamp <sven.langkamp@gmail.com>
3 * SPDX-FileCopyrightText: 2012 Dmitry Kazakov <dimula73@gmail.com>
4 * SPDX-FileCopyrightText: 2022 L. E. Segovia <amy@amyspark.me>
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9#ifndef KIS_BRUSH_VECTOR_APPLICATOR_H
10#define KIS_BRUSH_VECTOR_APPLICATOR_H
11
13
14#if !defined(XSIMD_NO_SUPPORTED_ARCHITECTURE) && XSIMD_UNIVERSAL_BUILD_PASS
15
17
18template<class V>
19struct FastRowProcessor {
20 FastRowProcessor(V *maskGenerator)
21 : d(maskGenerator->d.data())
22 {
23 }
24
25 template<typename _impl>
26 void process(float *buffer, int width, float y, float cosa, float sina, float centerX, float centerY);
27
28 typename V::Private *d;
29};
30
31template<class MaskGenerator, typename _impl>
32struct KisBrushMaskVectorApplicator : public KisBrushMaskScalarApplicator<MaskGenerator, _impl> {
33 KisBrushMaskVectorApplicator(MaskGenerator *maskGenerator)
34 : KisBrushMaskScalarApplicator<MaskGenerator, _impl>(maskGenerator)
35 {
36 }
37
38 void process(const QRect &rect) override
39 {
40 startProcessing(rect, TypeHelper<MaskGenerator, _impl>());
41 }
42
43protected:
44 void processVector(const QRect &rect);
45
46private:
47 template<class U, typename V>
48 struct TypeHelper {
49 };
50
51private:
52 template<class U>
53 inline void startProcessing(const QRect &rect, TypeHelper<U, xsimd::generic>)
54 {
56 }
57
58 template<class U, typename V>
59 inline void startProcessing(const QRect &rect, TypeHelper<U, V>)
60 {
62
63 if (m_maskGenerator->shouldVectorize()) {
64 processVector(rect);
65 } else {
67 }
68 }
69};
70
71template<class MaskGenerator, typename impl>
72void KisBrushMaskVectorApplicator<MaskGenerator, impl>::processVector(const QRect &rect)
73{
74 using float_v = xsimd::batch<float, impl>;
75
78
79 qreal random = 1.0;
80 quint8 *dabPointer = m_d->device->data() + rect.y() * rect.width() * m_d->pixelSize;
81 quint8 alphaValue = OPACITY_TRANSPARENT_U8;
82 // this offset is needed when brush size is smaller then fixed device size
83 int offset = (m_d->device->bounds().width() - rect.width()) * m_d->pixelSize;
84
85 int width = rect.width();
86
87 // We need to calculate with a multiple of the width of the simd register
88 size_t alignOffset = 0;
89 if (width % float_v::size != 0) {
90 alignOffset = float_v::size - (width % float_v::size);
91 }
92 size_t simdWidth = width + alignOffset;
93
94 auto *buffer =xsimd::vector_aligned_malloc<float>(simdWidth);
95
96 FastRowProcessor<MaskGenerator> processor(m_maskGenerator);
97
98 for (int y = rect.y(); y < rect.y() + rect.height(); y++) {
99 processor.template process<impl>(buffer, simdWidth, y, m_d->cosa, m_d->sina, m_d->centerX, m_d->centerY);
100
101 if (m_d->randomness != 0.0 || m_d->density != 1.0) {
102 for (int x = 0; x < width; x++) {
103 if (m_d->randomness != 0.0) {
104 random = (1.0 - m_d->randomness)
105 + m_d->randomness
107 }
108
109 alphaValue = quint8((OPACITY_OPAQUE_U8 - buffer[x] * 255) * random);
110
111 // avoid computation of random numbers if density is full
112 if (m_d->density != 1.0) {
113 // compute density only for visible pixels of the mask
114 if (alphaValue != OPACITY_TRANSPARENT_U8) {
116 .generateNormalized())) {
117 alphaValue = OPACITY_TRANSPARENT_U8;
118 }
119 }
120 }
121
122 if (m_d->color) {
123 memcpy(dabPointer, m_d->color, m_d->pixelSize);
124 }
125
126 m_d->colorSpace->applyAlphaU8Mask(dabPointer, &alphaValue, 1);
127 dabPointer += m_d->pixelSize;
128 }
129 } else if (m_d->color) {
130 m_d->colorSpace->fillInverseAlphaNormedFloatMaskWithColor(dabPointer, buffer, m_d->color, width);
131 dabPointer += width * m_d->pixelSize;
132 } else {
133 m_d->colorSpace->applyInverseNormedFloatMask(dabPointer, buffer, width);
134 dabPointer += width * m_d->pixelSize;
135 } // endfor x
136 dabPointer += offset;
137 } // endfor y
139}
140
141#endif /* !defined XSIMD_NO_SUPPORTED_ARCHITECTURE */
142
143#endif /* KIS_BRUSH_VECTOR_APPLICATOR_H */
const quint8 OPACITY_TRANSPARENT_U8
const quint8 OPACITY_OPAQUE_U8
virtual void applyAlphaU8Mask(quint8 *pixels, const quint8 *alpha, qint32 nPixels) const =0
virtual void fillInverseAlphaNormedFloatMaskWithColor(quint8 *pixels, const float *alpha, const quint8 *brushColor, qint32 nPixels) const =0
virtual void applyInverseNormedFloatMask(quint8 *pixels, const float *alpha, qint32 nPixels) const =0
void vector_aligned_free(const T *ptr) noexcept
void process(const QRect &rect) override