GCC Code Coverage Report


Directory: avs_core/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 0.0% 0 / 0 / 316
Functions: 0.0% 0 / 0 / 14
Branches: 0.0% 0 / 0 / 80

filters/overlay/OF_multiply.cpp
Line Branch Exec Source
1 // Avisynth v2.5. Copyright 2002 Ben Rudiak-Gould et al.
2 // http://avisynth.nl
3
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit
17 // http://www.gnu.org/copyleft/gpl.html .
18 //
19 // Linking Avisynth statically or dynamically with other modules is making a
20 // combined work based on Avisynth. Thus, the terms and conditions of the GNU
21 // General Public License cover the whole combination.
22 //
23 // As a special exception, the copyright holders of Avisynth give you
24 // permission to link Avisynth with independent modules that communicate with
25 // Avisynth solely through the interfaces defined in avisynth.h, regardless of the license
26 // terms of these independent modules, and to copy and distribute the
27 // resulting combined work under terms of your choice, provided that
28 // every copy of the combined work is accompanied by a complete copy of
29 // the source code of Avisynth (the version of Avisynth used to produce the
30 // combined work), being distributed under the terms of the GNU General
31 // Public License plus this exception. An independent module is a module
32 // which is not derived from or based on Avisynth, such as 3rd-party filters,
33 // import and export plugins, or graphical user interfaces.
34
35 // Overlay (c) 2003, 2004 by Klaus Post
36
37 #include "overlayfunctions.h"
38
39 #include <stdint.h>
40 #include <type_traits>
41 #ifdef INTEL_INTRINSICS
42 #include "intel/OF_multiply_sse.h"
43 #include "intel/OF_multiply_avx2.h"
44 #endif
45 void OL_MultiplyImage::DoBlendImageMask(ImageOverlayInternal* base, ImageOverlayInternal* overlay, ImageOverlayInternal* mask) {
46 if (bits_per_pixel == 8)
47 BlendImageMask<uint8_t>(base, overlay, mask);
48 else if(bits_per_pixel <= 16)
49 BlendImageMask<uint16_t>(base, overlay, mask);
50 //else if(bits_per_pixel == 32)
51 // BlendImageMask<float>(base, overlay, mask);
52
53 }
54
55 void OL_MultiplyImage::DoBlendImage(ImageOverlayInternal* base, ImageOverlayInternal* overlay) {
56 if (bits_per_pixel == 8)
57 BlendImage<uint8_t>(base, overlay);
58 else if(bits_per_pixel <= 16)
59 BlendImage<uint16_t>(base, overlay);
60 //else if(bits_per_pixel == 32)
61 // BlendImage<float>(base, overlay);
62 }
63
64 // mode multiply: Darkens the image in proportion to overlay lightness.
65
66 template<typename pixel_t, bool opacity_is_full, bool has_mask>
67 static void of_multiply_c(
68 int bits_per_pixel,
69 const float opacity_f,
70 const int opacity,
71 int width, int height,
72 const pixel_t* ovY,
73 int overlaypitch,
74 pixel_t* baseY, pixel_t* baseU, pixel_t* baseV,
75 int basepitch,
76 const pixel_t* maskY, const pixel_t* maskU, const pixel_t* maskV,
77 int maskpitch
78 )
79 {
80 const int max_pixel_value = (sizeof(pixel_t) == 1) ? 255 : (1 << bits_per_pixel) - 1;
81 const float factor = 1.0f / max_pixel_value;
82 const int half_i = 1 << (bits_per_pixel - 1);
83 const float half_f = (float)half_i;
84
85 float factor_mul_opacity;
86 if constexpr (opacity_is_full)
87 factor_mul_opacity = factor * 1.0f;
88 else
89 factor_mul_opacity = factor * opacity_f;
90
91 // start processing
92 for (int y = 0; y < height; y++) {
93 for (int x = 0; x < width; x++) {
94 int Y, U, V;
95
96 // generic, 8-16 bits
97 // This part re-appears in SSE code (non mod4 end-of-line fragment in C)
98 // Unlike the old integer version here is proper rounding
99 const float overlay_opacity_minus1 = ovY[x] * factor - 1.0f;
100 if constexpr (has_mask) {
101 float final_opacity;
102
103 final_opacity = maskY[x] * factor_mul_opacity;
104 auto Yfactor = 1.0f + overlay_opacity_minus1 * final_opacity;
105 Y = (int)(baseY[x] * Yfactor + 0.5f);
106
107 final_opacity = maskU[x] * factor_mul_opacity;
108 auto Ufactor = 1.0f + overlay_opacity_minus1 * final_opacity;
109 U = (int)(((float)baseU[x] - half_f) * Ufactor + half_f + 0.5f);
110
111 final_opacity = maskV[x] * factor_mul_opacity;
112 auto Vfactor = 1.0f + overlay_opacity_minus1 * final_opacity;
113 V = (int)(((float)baseV[x] - half_f) * Vfactor + half_f + 0.5f);
114 }
115 else {
116 const float common_factor = 1.0f + overlay_opacity_minus1 * opacity_f;
117
118 auto Yfactor = common_factor;
119 Y = (int)((float)baseY[x] * Yfactor + 0.5f);
120
121 auto Ufactor = common_factor;
122 U = (int)(((float)baseU[x] - half_f) * Ufactor + half_f + 0.5f);
123
124 auto Vfactor = common_factor;
125 V = (int)(((float)baseV[x] - half_f) * Vfactor + half_f + 0.5f);
126
127 }
128
129 baseU[x] = (pixel_t)U;
130 baseV[x] = (pixel_t)V;
131 baseY[x] = (pixel_t)Y;
132 }
133
134 if constexpr (has_mask) {
135 maskY += maskpitch;
136 maskU += maskpitch;
137 maskV += maskpitch;
138 }
139
140 baseY += basepitch;
141 baseU += basepitch;
142 baseV += basepitch;
143
144 ovY += overlaypitch;
145
146 }
147 }
148
149 // old, integer-inside C version.
150 // compared to the float-inside version, here is no proper rounding
151 // 8 bit processing is quicker though
152 template<typename pixel_t, bool opacity_is_full, bool has_mask>
153 static void of_multiply_c_old(
154 int bits_per_pixel,
155 const float opacity_f,
156 const int opacity,
157 int width, int height,
158 const pixel_t* ovY,
159 int overlaypitch,
160 pixel_t* baseY, pixel_t* baseU, pixel_t* baseV,
161 int basepitch,
162 const pixel_t* maskY, const pixel_t* maskU, const pixel_t* maskV,
163 int maskpitch
164 )
165 {
166 const int max_pixel_value = (sizeof(pixel_t) == 1) ? 255 : (1 << bits_per_pixel) - 1;
167 const int chroma_half_corr = (sizeof(pixel_t) == 1) ? 128 : (1 << (bits_per_pixel - 1));
168 const int pixel_range = max_pixel_value + 1;
169 const int MASK_CORR_SHIFT = (sizeof(pixel_t) == 1) ? 8 : bits_per_pixel;
170 const int inv_opacity = 256 - opacity;
171
172 // start processing
173 for (int y = 0; y < height; y++) {
174 for (int x = 0; x < width; x++) {
175 int Y, U, V;
176
177 // for 8 bit, which is a bit quicker with integer arithmetics
178 // avoid "uint16*uint16 can't get into int32" overflows
179 typedef typename std::conditional < sizeof(pixel_t) == 1, int, typename std::conditional < sizeof(pixel_t) == 2, int64_t, float>::type >::type result_t;
180
181 if constexpr (has_mask) {
182 result_t overlay_Y = ovY[x];
183
184 int final_opacity;
185 result_t inverse_final_opacity;
186
187 if constexpr (opacity_is_full)
188 final_opacity = maskY[x];
189 else
190 final_opacity = (maskY[x] * opacity) >> 8;
191 inverse_final_opacity = pixel_range - final_opacity;
192 Y = (int)((baseY[x] * (pixel_range * inverse_final_opacity + (overlay_Y * final_opacity))) >> (MASK_CORR_SHIFT * 2));
193
194 if constexpr (opacity_is_full)
195 final_opacity = maskU[x];
196 else
197 final_opacity = (maskU[x] * opacity) >> 8;
198 inverse_final_opacity = pixel_range - final_opacity;
199 U = (int)(((baseU[x] * inverse_final_opacity * pixel_range) + (final_opacity * (baseU[x] * overlay_Y + chroma_half_corr * (pixel_range - overlay_Y)))) >> (MASK_CORR_SHIFT * 2));
200
201 if constexpr (opacity_is_full)
202 final_opacity = maskV[x];
203 else
204 final_opacity = (maskV[x] * opacity) >> 8;
205 inverse_final_opacity = pixel_range - final_opacity;
206 V = (int)(((baseV[x] * inverse_final_opacity * pixel_range) + (final_opacity * (baseV[x] * overlay_Y + chroma_half_corr * (pixel_range - overlay_Y)))) >> (MASK_CORR_SHIFT * 2));
207 }
208 else {
209 // no mask clip
210 if constexpr (opacity_is_full) {
211 result_t ovYx = ovY[x];
212 Y = (int)((baseY[x] * ovYx) >> MASK_CORR_SHIFT);
213 U = (int)((baseU[x] * ovYx + chroma_half_corr * (pixel_range - ovYx)) >> MASK_CORR_SHIFT);
214 V = (int)((baseV[x] * ovYx + chroma_half_corr * (pixel_range - ovYx)) >> MASK_CORR_SHIFT);
215 }
216 else {
217 result_t ovYx = ovY[x];
218 result_t baseYx = baseY[x];
219 Y = (int)((baseYx * (pixel_range * inv_opacity + (ovYx * opacity))) >> (MASK_CORR_SHIFT + 8));
220 result_t baseUx = baseU[x];
221 U = (int)(((baseUx * inv_opacity * pixel_range) + (opacity * (baseUx * ovYx + chroma_half_corr * (pixel_range - ovYx)))) >> (MASK_CORR_SHIFT + 8));
222 result_t baseVx = baseV[x];
223 V = (int)(((baseVx * inv_opacity * pixel_range) + (opacity * (baseVx * ovYx + chroma_half_corr * (pixel_range - ovYx)))) >> (MASK_CORR_SHIFT + 8));
224 }
225 }
226
227 baseU[x] = (pixel_t)U;
228 baseV[x] = (pixel_t)V;
229 baseY[x] = (pixel_t)Y;
230 }
231
232 if constexpr (has_mask) {
233 maskY += maskpitch;
234 maskU += maskpitch;
235 maskV += maskpitch;
236 }
237
238 baseY += basepitch;
239 baseU += basepitch;
240 baseV += basepitch;
241
242 ovY += overlaypitch;
243
244 }
245 }
246
247 // mode multiply: Darkens the image in proportion to overlay lightness.
248 template<typename pixel_t>
249 void OL_MultiplyImage::BlendImageMask(ImageOverlayInternal* base, ImageOverlayInternal* overlay, ImageOverlayInternal* mask) {
250 pixel_t* baseY = reinterpret_cast<pixel_t*>(base->GetPtr(PLANAR_Y));
251 pixel_t* baseU = reinterpret_cast<pixel_t*>(base->GetPtr(PLANAR_U));
252 pixel_t* baseV = reinterpret_cast<pixel_t*>(base->GetPtr(PLANAR_V));
253
254 pixel_t* ovY = reinterpret_cast<pixel_t*>(overlay->GetPtr(PLANAR_Y));
255
256 pixel_t* maskY = reinterpret_cast<pixel_t*>(mask->GetPtr(PLANAR_Y));
257 pixel_t* maskU = reinterpret_cast<pixel_t*>(mask->GetPtr(PLANAR_U));
258 pixel_t* maskV = reinterpret_cast<pixel_t*>(mask->GetPtr(PLANAR_V));
259
260 const int basepitch = (base->pitch) / sizeof(pixel_t);
261 const int overlaypitch = (overlay->pitch) / sizeof(pixel_t);
262 const int maskpitch = (mask->pitch) / sizeof(pixel_t);
263
264 int w = base->w();
265 int h = base->h();
266 #ifdef INTEL_INTRINSICS
267 if (!!(env->GetCPUFlags() & CPUF_AVX2))
268 {
269 if (opacity == 256)
270 of_multiply_avx2<pixel_t, true, true>(bits_per_pixel, opacity_f, opacity, w, h, ovY, overlaypitch, baseY, baseU, baseV, basepitch, maskY, maskU, maskV, maskpitch);
271 else
272 of_multiply_avx2<pixel_t, false, true>(bits_per_pixel, opacity_f, opacity, w, h, ovY, overlaypitch, baseY, baseU, baseV, basepitch, maskY, maskU, maskV, maskpitch);
273 }
274 else if (!!(env->GetCPUFlags() & CPUF_SSE4_1))
275 {
276 if (opacity == 256)
277 of_multiply_sse41<pixel_t, true, true>(bits_per_pixel, opacity_f, opacity, w, h, ovY, overlaypitch, baseY, baseU, baseV, basepitch, maskY, maskU, maskV, maskpitch);
278 else
279 of_multiply_sse41<pixel_t, false, true>(bits_per_pixel, opacity_f, opacity, w, h, ovY, overlaypitch, baseY, baseU, baseV, basepitch, maskY, maskU, maskV, maskpitch);
280 }
281 else
282 #endif
283 {
284 if (opacity == 256)
285 of_multiply_c<pixel_t, true, true>(bits_per_pixel, opacity_f, opacity, w, h, ovY, overlaypitch, baseY, baseU, baseV, basepitch, maskY, maskU, maskV, maskpitch);
286 else
287 of_multiply_c<pixel_t, false, true>(bits_per_pixel, opacity_f, opacity, w, h, ovY, overlaypitch, baseY, baseU, baseV, basepitch, maskY, maskU, maskV, maskpitch);
288 }
289 }
290
291 // no mask involved
292 template<typename pixel_t>
293 void OL_MultiplyImage::BlendImage(ImageOverlayInternal* base, ImageOverlayInternal* overlay) {
294 pixel_t* baseY = reinterpret_cast<pixel_t*>(base->GetPtr(PLANAR_Y));
295 pixel_t* baseU = reinterpret_cast<pixel_t*>(base->GetPtr(PLANAR_U));
296 pixel_t* baseV = reinterpret_cast<pixel_t*>(base->GetPtr(PLANAR_V));
297
298 pixel_t* ovY = reinterpret_cast<pixel_t*>(overlay->GetPtr(PLANAR_Y));
299
300 const int basepitch = (base->pitch) / sizeof(pixel_t);
301 const int overlaypitch = (overlay->pitch) / sizeof(pixel_t);
302
303 int w = base->w();
304 int h = base->h();
305 #ifdef INTEL_INTRINSICS
306 if (!!(env->GetCPUFlags() & CPUF_AVX2))
307 {
308 if (opacity == 256)
309 of_multiply_avx2<pixel_t, true, false>(bits_per_pixel, opacity_f, opacity, w, h, ovY, overlaypitch, baseY, baseU, baseV, basepitch, nullptr, nullptr, nullptr, 0);
310 else
311 of_multiply_avx2<pixel_t, false, false>(bits_per_pixel, opacity_f, opacity, w, h, ovY, overlaypitch, baseY, baseU, baseV, basepitch, nullptr, nullptr, nullptr, 0);
312 }
313 else if (!!(env->GetCPUFlags() & CPUF_SSE4_1))
314 {
315 if (opacity == 256)
316 of_multiply_sse41<pixel_t, true, false>(bits_per_pixel, opacity_f, opacity, w, h, ovY, overlaypitch, baseY, baseU, baseV, basepitch, nullptr, nullptr, nullptr, 0);
317 else
318 of_multiply_sse41<pixel_t, false, false>(bits_per_pixel, opacity_f, opacity, w, h, ovY, overlaypitch, baseY, baseU, baseV, basepitch, nullptr, nullptr, nullptr, 0);
319 }
320 else
321 #endif
322 {
323 if (opacity == 256)
324 of_multiply_c<pixel_t, true, false>(bits_per_pixel, opacity_f, opacity, w, h, ovY, overlaypitch, baseY, baseU, baseV, basepitch, nullptr, nullptr, nullptr, 0);
325 else
326 of_multiply_c<pixel_t, false, false>(bits_per_pixel, opacity_f, opacity, w, h, ovY, overlaypitch, baseY, baseU, baseV, basepitch, nullptr, nullptr, nullptr, 0);
327 }
328 }
329