Krita Source Code Documentation
Loading...
Searching...
No Matches
OverCompositor32< channels_type, pixel_type, alphaLocked, allChannelsFlag > Struct Template Reference

#include <KoOptimizedCompositeOpOver32.h>

Classes

struct  ParamsWrapper
 

Static Public Member Functions

template<bool haveMask, typename _impl >
static ALWAYS_INLINE void compositeOnePixelScalar (const channels_type *src, channels_type *dst, const quint8 *mask, float opacity, const ParamsWrapper &oparams)
 
template<bool haveMask, bool src_aligned, typename _impl >
static ALWAYS_INLINE void compositeVector (const quint8 *src, quint8 *dst, const quint8 *mask, float opacity, const ParamsWrapper &oparams)
 

Detailed Description

template<typename channels_type, typename pixel_type, bool alphaLocked, bool allChannelsFlag>
struct OverCompositor32< channels_type, pixel_type, alphaLocked, allChannelsFlag >

Definition at line 20 of file KoOptimizedCompositeOpOver32.h.

Member Function Documentation

◆ compositeOnePixelScalar()

template<typename channels_type , typename pixel_type , bool alphaLocked, bool allChannelsFlag>
template<bool haveMask, typename _impl >
static ALWAYS_INLINE void OverCompositor32< channels_type, pixel_type, alphaLocked, allChannelsFlag >::compositeOnePixelScalar ( const channels_type * src,
channels_type * dst,
const quint8 * mask,
float opacity,
const ParamsWrapper & oparams )
inlinestatic

Definition at line 121 of file KoOptimizedCompositeOpOver32.h.

122 {
123 using namespace Arithmetic;
124 const qint32 alpha_pos = 3;
125
126 const float uint8Rec1 = 1.0f / 255.0f;
127 const float uint8Max = 255.0f;
128
129 float srcAlpha = src[alpha_pos];
130 srcAlpha *= opacity;
131
132 if (haveMask) {
133 srcAlpha *= float(*mask) * uint8Rec1;
134 }
135
136 if (srcAlpha != 0.0f) {
137
138 float dstAlpha = dst[alpha_pos];
139 float srcBlendNorm = NAN;
140
141 if (alphaLocked || dstAlpha == uint8Max) {
142 srcBlendNorm = srcAlpha * uint8Rec1;
143 } else if (dstAlpha == 0.0f) {
144 dstAlpha = srcAlpha;
145 srcBlendNorm = 1.0f;
146
147 if (!allChannelsFlag) {
148 auto *d = reinterpret_cast<pixel_type*>(dst);
149 *d = 0; // dstAlpha is already null
150 }
151 } else {
152 dstAlpha += (uint8Max - dstAlpha) * srcAlpha * uint8Rec1;
153 // Optimized version of:
154 // srcBlendNorm = srcAlpha / dstAlpha);
155 srcBlendNorm = OptiDiv<_impl>::divScalar(srcAlpha, dstAlpha);
156 }
157
158 if(allChannelsFlag) {
159 if (srcBlendNorm == 1.0f) {
160 if (!alphaLocked) {
161 const auto *s = reinterpret_cast<const pixel_type*>(src);
162 auto *d = reinterpret_cast<pixel_type*>(dst);
163 *d = *s;
164 } else {
165 dst[0] = src[0];
166 dst[1] = src[1];
167 dst[2] = src[2];
168 }
169 } else if (srcBlendNorm != 0.0f){
170 dst[0] = KoStreamedMath<_impl>::lerp_mixed_u8_float(dst[0], src[0], srcBlendNorm);
171 dst[1] = KoStreamedMath<_impl>::lerp_mixed_u8_float(dst[1], src[1], srcBlendNorm);
172 dst[2] = KoStreamedMath<_impl>::lerp_mixed_u8_float(dst[2], src[2], srcBlendNorm);
173 }
174 } else {
175 const QBitArray &channelFlags = oparams.channelFlags;
176
177 if (srcBlendNorm == 1.0f) {
178 if(channelFlags.at(0)) dst[0] = src[0];
179 if(channelFlags.at(1)) dst[1] = src[1];
180 if(channelFlags.at(2)) dst[2] = src[2];
181 } else if (srcBlendNorm != 0.0f) {
182 if(channelFlags.at(0)) dst[0] = KoStreamedMath<_impl>::lerp_mixed_u8_float(dst[0], src[0], srcBlendNorm);
183 if(channelFlags.at(1)) dst[1] = KoStreamedMath<_impl>::lerp_mixed_u8_float(dst[1], src[1], srcBlendNorm);
184 if(channelFlags.at(2)) dst[2] = KoStreamedMath<_impl>::lerp_mixed_u8_float(dst[2], src[2], srcBlendNorm);
185 }
186 }
187
188 if (!alphaLocked) {
189 dst[alpha_pos] = KoStreamedMath<_impl>::round_float_to_u8(dstAlpha);
190 }
191 }
192 }
static quint8 lerp_mixed_u8_float(quint8 a, quint8 b, float alpha)
static quint8 round_float_to_u8(float x)
static ALWAYS_INLINE float divScalar(const float &divident, const float &divisor)

References OverCompositor32< channels_type, pixel_type, alphaLocked, allChannelsFlag >::ParamsWrapper::channelFlags, OptiDiv< _impl >::divScalar(), KoStreamedMath< _impl >::lerp_mixed_u8_float(), and KoStreamedMath< _impl >::round_float_to_u8().

◆ compositeVector()

template<typename channels_type , typename pixel_type , bool alphaLocked, bool allChannelsFlag>
template<bool haveMask, bool src_aligned, typename _impl >
static ALWAYS_INLINE void OverCompositor32< channels_type, pixel_type, alphaLocked, allChannelsFlag >::compositeVector ( const quint8 * src,
quint8 * dst,
const quint8 * mask,
float opacity,
const ParamsWrapper & oparams )
inlinestatic

The value of new_alpha can have some zero values, which will result in NaN values while division. But when converted to integers these NaN values will be converted to zeroes, which is exactly what we need

Definition at line 31 of file KoOptimizedCompositeOpOver32.h.

32 {
33 Q_UNUSED(oparams);
34
35 using float_v = typename KoStreamedMath<_impl>::float_v;
36
37 float_v src_alpha = KoStreamedMath<_impl>::template fetch_alpha_32<src_aligned>(src);
38 float_v dst_alpha;
39
40 const bool haveOpacity = opacity != 1.0f;
41 const float_v opacity_norm_vec(opacity);
42
43 const float_v uint8Max(255.0f);
44 const float_v uint8MaxRec1(1.0f / 255.0f);
45 const float_v zeroValue(0);
46 const float_v oneValue(1);
47
48 src_alpha *= opacity_norm_vec;
49
50 if (haveMask) {
51 const float_v mask_vec = KoStreamedMath<_impl>::fetch_mask_8(mask);
52 src_alpha *= mask_vec * uint8MaxRec1;
53 }
54
55 // The source cannot change the colors in the destination,
56 // since its fully transparent
57 if (xsimd::all(src_alpha == zeroValue)) {
58 return;
59 }
60
61 dst_alpha = KoStreamedMath<_impl>::template fetch_alpha_32<true>(dst);
62
63 float_v src_c1;
64 float_v src_c2;
65 float_v src_c3;
66
67 float_v dst_c1;
68 float_v dst_c2;
69 float_v dst_c3;
70
71
72 KoStreamedMath<_impl>::template fetch_colors_32<src_aligned>(src, src_c1, src_c2, src_c3);
73 float_v src_blend;
74 float_v new_alpha;
75
76 if (xsimd::all(dst_alpha == uint8Max)) {
77 new_alpha = dst_alpha;
78 src_blend = src_alpha * uint8MaxRec1;
79 } else if (xsimd::all(dst_alpha == zeroValue)) {
80 new_alpha = src_alpha;
81 src_blend = oneValue;
82 } else {
89 new_alpha = dst_alpha + (uint8Max - dst_alpha) * src_alpha * uint8MaxRec1;
90
91 // Optimized version of:
92 // src_blend = src_alpha / new_alpha;
93 src_blend = OptiDiv<_impl>::divVector(src_alpha, new_alpha);
94
95 }
96
97 if (!xsimd::all(src_blend == oneValue)) {
98 KoStreamedMath<_impl>::template fetch_colors_32<true>(dst, dst_c1, dst_c2, dst_c3);
99
100 dst_c1 = src_blend * (src_c1 - dst_c1) + dst_c1;
101 dst_c2 = src_blend * (src_c2 - dst_c2) + dst_c2;
102 dst_c3 = src_blend * (src_c3 - dst_c3) + dst_c3;
103
104 } else {
105 if (!haveMask && !haveOpacity) {
106 memcpy(dst, src, 4 * float_v::size);
107 return;
108 } else {
109 // opacity has changed the alpha of the source,
110 // so we can't just memcpy the bytes
111 dst_c1 = src_c1;
112 dst_c2 = src_c2;
113 dst_c3 = src_c3;
114 }
115 }
116
117 KoStreamedMath<_impl>::write_channels_32(dst, new_alpha, dst_c1, dst_c2, dst_c3);
118 }
static void write_channels_32(void *data, const float_v alpha, const float_v c1, const float_v c2, const float_v c3)
xsimd::batch< float, _impl > float_v
static float_v fetch_mask_8(const quint8 *data)
static ALWAYS_INLINE float_v divVector(const float_v &divident, const float_v &divisor)

References OptiDiv< _impl >::divVector(), KoStreamedMath< _impl >::fetch_mask_8(), and KoStreamedMath< _impl >::write_channels_32().


The documentation for this struct was generated from the following file: