Krita Source Code Documentation
Loading...
Searching...
No Matches
KoAlphaMaskApplicator.h
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2020 Dmitry Kazakov <dimula73@gmail.com>
3 * SPDX-FileCopyrightText: 2022 L. E. Segovia <amy@amyspark.me>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
8#ifndef KOALPHAMASKAPPLICATOR_H
9#define KOALPHAMASKAPPLICATOR_H
10
12#include "KoColorSpaceTraits.h"
14
15
16template<typename _channels_type_,
17 int _channels_nb_,
18 int _alpha_pos_,
19 typename _impl,
20 typename EnableDummyType = void>
22{
23 void applyInverseNormedFloatMask(quint8 *pixels,
24 const float *alpha,
25 qint32 nPixels) const override {
27 _channels_type_,
28 _channels_nb_,
29 _alpha_pos_>::
30 applyInverseAlphaNormedFloatMask(pixels, alpha, nPixels);
31 }
32
34 const float * alpha,
35 const quint8 *brushColor,
36 qint32 nPixels) const override {
38 _channels_type_,
39 _channels_nb_,
40 _alpha_pos_>::
41 fillInverseAlphaNormedFloatMaskWithColor(pixels, alpha, brushColor, nPixels);
42 }
43
44 void fillGrayBrushWithColor(quint8 *dst, const QRgb *brush, quint8 *brushColor, qint32 nPixels) const override {
46 _channels_type_,
47 _channels_nb_,
48 _alpha_pos_>::
49 fillGrayBrushWithColor(dst, brush, brushColor, nPixels);
50 }
51};
52
53#if !defined(XSIMD_NO_SUPPORTED_ARCHITECTURE)
54
55#include "KoStreamedMath.h"
56
57template<typename _impl>
59 quint8, 4, 3, _impl,
60 typename std::enable_if<!std::is_same<_impl, xsimd::generic>::value>::type> : public KoAlphaMaskApplicatorBase
61{
65
66 static constexpr int numChannels = 4;
67 static constexpr int alphaPos = 3;
68
69 void applyInverseNormedFloatMask(quint8 *pixels,
70 const float *alpha,
71 qint32 nPixels) const override
72 {
73 const int block1 = nPixels / static_cast<int>(float_v::size);
74 const int block2 = nPixels % static_cast<int>(float_v::size);
75 const int vectorPixelStride = numChannels * static_cast<int>(float_v::size);
76
77 for (int i = 0; i < block1; i++) {
78 const auto maskAlpha = float_v::load_unaligned(alpha);
79
80 auto data_i = uint_v::load_unaligned(reinterpret_cast<const quint32 *>(pixels));
81
82 const auto pixelAlpha = xsimd::to_float(xsimd::bitwise_cast_compat<int>(data_i >> 24U)) * (float_v(1.0f) - maskAlpha);
83
84 const quint32 colorChannelsMask = 0x00FFFFFF;
85
86 const uint_v pixelAlpha_i = xsimd::bitwise_cast_compat<unsigned int>(xsimd::nearbyint_as_int(pixelAlpha));
87 data_i = (data_i & colorChannelsMask) | (pixelAlpha_i << 24);
88 data_i.store_unaligned(reinterpret_cast<typename uint_v::value_type *>(pixels));
89
90 pixels += vectorPixelStride;
91 alpha += float_v::size;
92 }
93
95 applyInverseAlphaNormedFloatMask(pixels, alpha, block2);
96 }
97
99 const float * alpha,
100 const quint8 *brushColor,
101 qint32 nPixels) const override {
102 const int block1 = nPixels / static_cast<int>(float_v::size);
103 const int block2 = nPixels % static_cast<int>(float_v::size);
104 const int vectorPixelStride = numChannels * static_cast<int>(float_v::size);
105 const uint_v brushColor_i(*reinterpret_cast<const quint32*>(brushColor) & 0x00FFFFFFu);
106
107 for (int i = 0; i < block1; i++) {
108 const auto maskAlpha = float_v::load_unaligned(alpha);
109 const auto pixelAlpha = float_v(255.0f) * (float_v(1.0f) - maskAlpha);
110
111 const uint_v pixelAlpha_i = xsimd::bitwise_cast_compat<unsigned int>(xsimd::nearbyint_as_int(pixelAlpha));
112 const uint_v data_i = brushColor_i | (pixelAlpha_i << 24);
113 data_i.store_unaligned(reinterpret_cast<typename uint_v::value_type *>(pixels));
114
115 pixels += vectorPixelStride;
116 alpha += float_v::size;
117 }
118
120 fillInverseAlphaNormedFloatMaskWithColor(pixels, alpha, brushColor, block2);
121 }
122
123 static inline uint_v multiply(uint_v a, uint_v b)
124 {
125 const uint_v c = a * b + 0x80u;
126 return ((c >> 8) + c) >> 8;
127 }
128
129 void fillGrayBrushWithColor(quint8 *dst, const QRgb *brush, quint8 *brushColor, qint32 nPixels) const override {
130 const int block1 = nPixels / static_cast<int>(float_v::size);
131 const int block2 = nPixels % static_cast<int>(float_v::size);
132 const int vectorPixelStride = numChannels * static_cast<int>(float_v::size);
133 const uint_v brushColor_i(*reinterpret_cast<const quint32*>(brushColor) & 0x00FFFFFFu);
134
135 const uint_v redChannelMask(0xFF);
136
137 for (int i = 0; i < block1; i++) {
138 const auto maskPixels = uint_v::load_unaligned(reinterpret_cast<const quint32*>(brush));
139
140 const uint_v pixelAlpha = maskPixels >> 24;
141 const uint_v pixelRed = maskPixels & redChannelMask;
142 const uint_v pixelAlpha_i = multiply(redChannelMask - pixelRed, pixelAlpha);
143
144 const uint_v data_i = brushColor_i | (pixelAlpha_i << 24);
145 data_i.store_unaligned(reinterpret_cast<typename uint_v::value_type *>(dst));
146
147 dst += vectorPixelStride;
148 brush += float_v::size;
149 }
150
152 fillGrayBrushWithColor(dst, brush, brushColor, block2);
153 }
154};
155
156#endif /* !defined(XSIMD_NO_SUPPORTED_ARCHITECTURE) */
157
158#endif // KOALPHAMASKAPPLICATOR_H
unsigned int QRgb
void fillInverseAlphaNormedFloatMaskWithColor(quint8 *pixels, const float *alpha, const quint8 *brushColor, qint32 nPixels) const override
void fillGrayBrushWithColor(quint8 *dst, const QRgb *brush, quint8 *brushColor, qint32 nPixels) const override
void fillInverseAlphaNormedFloatMaskWithColor(quint8 *pixels, const float *alpha, const quint8 *brushColor, qint32 nPixels) const override
void fillGrayBrushWithColor(quint8 *dst, const QRgb *brush, quint8 *brushColor, qint32 nPixels) const override
void applyInverseNormedFloatMask(quint8 *pixels, const float *alpha, qint32 nPixels) const override
static void fillInverseAlphaNormedFloatMaskWithColor(quint8 *pixels, const float *alpha, const quint8 *brushColor, qint32 nPixels)
static void applyInverseAlphaNormedFloatMask(quint8 *pixels, const float *alpha, qint32 nPixels)
static void fillGrayBrushWithColor(quint8 *pixels, const QRgb *brush, quint8 *brushColor, qint32 nPixels)
xsimd::batch< unsigned int, _impl > uint_v
xsimd::batch< float, _impl > float_v
xsimd::batch< int, _impl > int_v