GCC Code Coverage Report


Directory: avs_core/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 30.1% 47 / 0 / 156
Functions: 40.0% 6 / 0 / 15
Branches: 29.1% 32 / 0 / 110

filters/overlay/blend_common.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 <avs/config.h>
38
39 #include "blend_common.h"
40 #include "overlayfunctions.h"
41
42 #include <stdint.h>
43 #include <cstring>
44 #include <type_traits>
45
46
47 /******************************
48 ********* Mode: Blend ********
49 ******************************/
50 // ---------------------------------------------------------------------------
51 // Overlay blend masked getter — returns masked_merge_avx2_impl instantiation.
52 // is_chroma=false -> always MASK444 (luma).
53 // is_chroma=true -> placement-aware maskMode (chroma).
54 // ---------------------------------------------------------------------------
55
56 13416 masked_merge_fn_t* get_overlay_blend_masked_fn_c(bool is_chroma, MaskMode maskMode)
57 {
58 #define DISPATCH_OVERLAY_BLEND_C(MaskType) \
59 return is_chroma ? masked_merge_c_impl<MaskType> \
60 : masked_merge_c_impl<MASK444>;
61
62
7/9
✓ Branch 2 → 3 taken 2886 times.
✓ Branch 2 → 4 taken 2171 times.
✓ Branch 2 → 8 taken 1820 times.
✓ Branch 2 → 12 taken 1456 times.
✓ Branch 2 → 16 taken 2171 times.
✓ Branch 2 → 20 taken 1456 times.
✓ Branch 2 → 24 taken 1456 times.
✗ Branch 2 → 28 not taken.
✗ Branch 2 → 32 not taken.
13416 switch (maskMode) {
63 2886 case MASK444: DISPATCH_OVERLAY_BLEND_C(MASK444)
64
1/2
✓ Branch 4 → 5 taken 2171 times.
✗ Branch 4 → 6 not taken.
2171 case MASK420: DISPATCH_OVERLAY_BLEND_C(MASK420)
65
1/2
✓ Branch 8 → 9 taken 1820 times.
✗ Branch 8 → 10 not taken.
1820 case MASK420_MPEG2: DISPATCH_OVERLAY_BLEND_C(MASK420_MPEG2)
66
1/2
✓ Branch 12 → 13 taken 1456 times.
✗ Branch 12 → 14 not taken.
1456 case MASK420_TOPLEFT: DISPATCH_OVERLAY_BLEND_C(MASK420_TOPLEFT)
67
1/2
✓ Branch 16 → 17 taken 2171 times.
✗ Branch 16 → 18 not taken.
2171 case MASK422: DISPATCH_OVERLAY_BLEND_C(MASK422)
68
1/2
✓ Branch 20 → 21 taken 1456 times.
✗ Branch 20 → 22 not taken.
1456 case MASK422_MPEG2: DISPATCH_OVERLAY_BLEND_C(MASK422_MPEG2)
69
1/2
✓ Branch 24 → 25 taken 1456 times.
✗ Branch 24 → 26 not taken.
1456 case MASK422_TOPLEFT: DISPATCH_OVERLAY_BLEND_C(MASK422_TOPLEFT)
70 case MASK411: DISPATCH_OVERLAY_BLEND_C(MASK411)
71 }
72 #undef DISPATCH_OVERLAY_BLEND_C
73 return masked_merge_c_impl<MASK444>; // unreachable
74 }
75
76 // and for float:
77 858 masked_merge_float_fn_t* get_overlay_blend_masked_float_fn_c(bool is_chroma, MaskMode maskMode)
78 {
79 #define DISPATCH_OVERLAY_BLEND_FLOAT_C(MaskType) \
80 return is_chroma ? masked_merge_float_c_impl<MaskType> \
81 : masked_merge_float_c_impl<MASK444>;
82
83
3/9
✓ Branch 2 → 3 taken 286 times.
✓ Branch 2 → 4 taken 286 times.
✗ Branch 2 → 8 not taken.
✗ Branch 2 → 12 not taken.
✓ Branch 2 → 16 taken 286 times.
✗ Branch 2 → 20 not taken.
✗ Branch 2 → 24 not taken.
✗ Branch 2 → 28 not taken.
✗ Branch 2 → 32 not taken.
858 switch (maskMode) {
84 286 case MASK444: DISPATCH_OVERLAY_BLEND_FLOAT_C(MASK444)
85
1/2
✓ Branch 4 → 5 taken 286 times.
✗ Branch 4 → 6 not taken.
286 case MASK420: DISPATCH_OVERLAY_BLEND_FLOAT_C(MASK420)
86 case MASK420_MPEG2: DISPATCH_OVERLAY_BLEND_FLOAT_C(MASK420_MPEG2)
87 case MASK420_TOPLEFT: DISPATCH_OVERLAY_BLEND_FLOAT_C(MASK420_TOPLEFT)
88
1/2
✓ Branch 16 → 17 taken 286 times.
✗ Branch 16 → 18 not taken.
286 case MASK422: DISPATCH_OVERLAY_BLEND_FLOAT_C(MASK422)
89 case MASK422_MPEG2: DISPATCH_OVERLAY_BLEND_FLOAT_C(MASK422_MPEG2)
90 case MASK422_TOPLEFT: DISPATCH_OVERLAY_BLEND_FLOAT_C(MASK422_TOPLEFT)
91 case MASK411: DISPATCH_OVERLAY_BLEND_FLOAT_C(MASK411)
92 }
93 #undef DISPATCH_OVERLAY_BLEND_FLOAT_C
94 return masked_merge_float_c_impl<MASK444>; // unreachable
95 }
96
97 /*
98 // Scalar division — used in reference C, constexpr-friendly
99 template<int bits_per_pixel>
100 inline int magic_div(uint32_t tmp) {
101 constexpr MagicDiv magic = get_magic_div(bits_per_pixel);
102 if constexpr (bits_per_pixel == 8)
103 // mimics: mulhi_epu16(x, 0x8081) >> 7
104 return (int)(((uint32_t)tmp * magic.div) >> (16 + magic.shift));
105 else
106 // mimics: mul_epu32(x, div) >> (32 + shift)
107 return (int)(((uint64_t)tmp * magic.div) >> (32 + magic.shift));
108 }
109 */
110
111 /*****************************************************
112 ********* Family 1: weighted_merge (no mask) ********
113 *****************************************************/
114
115 // weight + invweight == 32768; kernel: (p1*inv + p2*w + 16384) >> 15
116 // Intentionally matches the SIMD >> 15 path (old C used >> 16 with weights summing to 32767).
117 template<typename pixel_t>
118 24 static void weighted_merge_impl_c(BYTE* p1, const BYTE* p2,
119 int p1_pitch, int p2_pitch,
120 int width, int height,
121 int weight, int invweight)
122 {
123
4/4
void weighted_merge_impl_c<unsigned char>(unsigned char*, unsigned char const*, int, int, int, int, int, int):
✓ Branch 7 → 3 taken 72 times.
✓ Branch 7 → 8 taken 8 times.
void weighted_merge_impl_c<unsigned short>(unsigned char*, unsigned char const*, int, int, int, int, int, int):
✓ Branch 7 → 3 taken 160 times.
✓ Branch 7 → 8 taken 16 times.
256 for (int y = 0; y < height; y++) {
124
4/4
void weighted_merge_impl_c<unsigned char>(unsigned char*, unsigned char const*, int, int, int, int, int, int):
✓ Branch 5 → 4 taken 2504 times.
✓ Branch 5 → 6 taken 72 times.
void weighted_merge_impl_c<unsigned short>(unsigned char*, unsigned char const*, int, int, int, int, int, int):
✓ Branch 5 → 4 taken 2872 times.
✓ Branch 5 → 6 taken 160 times.
5608 for (int x = 0; x < width; x++) {
125 5376 reinterpret_cast<pixel_t*>(p1)[x] = (pixel_t)(
126 5376 (reinterpret_cast<const pixel_t*>(p1)[x] * invweight +
127 5376 reinterpret_cast<const pixel_t*>(p2)[x] * weight + 16384) >> 15);
128 }
129 232 p1 += p1_pitch;
130 232 p2 += p2_pitch;
131 }
132 24 }
133
134 // merge, handle the two extrems at plane level if it wasn't at clip level
135 void weighted_merge_return_a_or_b(BYTE* p1, const BYTE* p2,
136 int p1_pitch, int p2_pitch,
137 int width, int height,
138 int weight, int invweight,
139 int bits_per_pixel)
140 {
141 // called either with weight==0, invweight==32768 or the opposite
142 if (weight == 0) return; // keep p1 as-is
143
144 const int pixelsize = bits_per_pixel == 8 ? 1 : bits_per_pixel <= 16 ? 2 : 4;
145 const int rowsize = width * pixelsize;
146
147 if (invweight == 0) {
148 // like bitblt
149 for (int y = 0; y < height; y++) {
150 memcpy(p1, p2, rowsize);
151 p1 += p1_pitch;
152 p2 += p2_pitch;
153 }
154 }
155 }
156
157 24 void weighted_merge_c(BYTE* p1, const BYTE* p2,
158 int p1_pitch, int p2_pitch,
159 int width, int height,
160 int weight, int invweight,
161 int bits_per_pixel)
162 {
163
2/2
✓ Branch 2 → 3 taken 8 times.
✓ Branch 2 → 4 taken 16 times.
24 if (bits_per_pixel == 8)
164 8 weighted_merge_impl_c<uint8_t>(p1, p2, p1_pitch, p2_pitch, width, height, weight, invweight);
165 else
166 16 weighted_merge_impl_c<uint16_t>(p1, p2, p1_pitch, p2_pitch, width, height, weight, invweight);
167 24 }
168
169 16 void weighted_merge_float_c(BYTE* p1, const BYTE* p2,
170 int p1_pitch, int p2_pitch,
171 int width, int height,
172 float weight_f)
173 {
174 16 const float invweight_f = 1.0f - weight_f;
175
2/2
✓ Branch 7 → 3 taken 76 times.
✓ Branch 7 → 8 taken 16 times.
92 for (int y = 0; y < height; y++) {
176
2/2
✓ Branch 5 → 4 taken 1292 times.
✓ Branch 5 → 6 taken 76 times.
1368 for (int x = 0; x < width; x++) {
177 1292 reinterpret_cast<float*>(p1)[x] =
178 1292 reinterpret_cast<const float*>(p1)[x] * invweight_f +
179 1292 reinterpret_cast<const float*>(p2)[x] * weight_f;
180 }
181 76 p1 += p1_pitch;
182 76 p2 += p2_pitch;
183 }
184 16 }
185
186 /***************************************
187 ********* Mode: Lighten/Darken ********
188 ***************************************/
189
190 typedef int (OverlayCCompare)(BYTE, BYTE);
191
192 template<typename pixel_t, bool darken /* OverlayCCompare<pixel_t> compare*/>
193 static void overlay_darklighten_c(BYTE *p1Y_8, BYTE *p1U_8, BYTE *p1V_8, const BYTE *p2Y_8, const BYTE *p2U_8, const BYTE *p2V_8, int p1_pitch, int p2_pitch, int width, int height) {
194 pixel_t* p1Y = reinterpret_cast<pixel_t *>(p1Y_8);
195 pixel_t* p1U = reinterpret_cast<pixel_t *>(p1U_8);
196 pixel_t* p1V = reinterpret_cast<pixel_t *>(p1V_8);
197
198 const pixel_t* p2Y = reinterpret_cast<const pixel_t *>(p2Y_8);
199 const pixel_t* p2U = reinterpret_cast<const pixel_t *>(p2U_8);
200 const pixel_t* p2V = reinterpret_cast<const pixel_t *>(p2V_8);
201
202 // pitches are already scaled
203 //p1_pitch /= sizeof(pixel_t);
204 //p2_pitch /= sizeof(pixel_t);
205
206 for (int y = 0; y < height; y++) {
207 for (int x = 0; x < width; x++) {
208 int mask = darken ? (p2Y[x] <= p1Y[x]) : (p2Y[x] >= p1Y[x]); // compare(p1Y[x], p2Y[x]);
209 p1Y[x] = overlay_blend_opaque_c_core<pixel_t>(p1Y[x], p2Y[x], mask);
210 p1U[x] = overlay_blend_opaque_c_core<pixel_t>(p1U[x], p2U[x], mask);
211 p1V[x] = overlay_blend_opaque_c_core<pixel_t>(p1V[x], p2V[x], mask);
212 }
213
214 p1Y += p1_pitch;
215 p1U += p1_pitch;
216 p1V += p1_pitch;
217
218 p2Y += p2_pitch;
219 p2U += p2_pitch;
220 p2V += p2_pitch;
221 }
222 }
223
224 // Exported function
225 template<typename pixel_t>
226 void overlay_darken_c(BYTE *p1Y_8, BYTE *p1U_8, BYTE *p1V_8, const BYTE *p2Y_8, const BYTE *p2U_8, const BYTE *p2V_8, int p1_pitch, int p2_pitch, int width, int height) {
227 overlay_darklighten_c<pixel_t, true /*overlay_darken_c_cmp */>(p1Y_8, p1U_8, p1V_8, p2Y_8, p2U_8, p2V_8, p1_pitch, p2_pitch, width, height);
228 }
229 // instantiate
230 template void overlay_darken_c<uint8_t>(BYTE *p1Y_8, BYTE *p1U_8, BYTE *p1V_8, const BYTE *p2Y_8, const BYTE *p2U_8, const BYTE *p2V_8, int p1_pitch, int p2_pitch, int width, int height);
231 template void overlay_darken_c<uint16_t>(BYTE *p1Y_8, BYTE *p1U_8, BYTE *p1V_8, const BYTE *p2Y_8, const BYTE *p2U_8, const BYTE *p2V_8, int p1_pitch, int p2_pitch, int width, int height);
232
233 template<typename pixel_t>
234 void overlay_lighten_c(BYTE *p1Y_8, BYTE *p1U_8, BYTE *p1V_8, const BYTE *p2Y_8, const BYTE *p2U_8, const BYTE *p2V_8, int p1_pitch, int p2_pitch, int width, int height) {
235 overlay_darklighten_c<pixel_t, false /*overlay_lighten_c_cmp*/>(p1Y_8, p1U_8, p1V_8, p2Y_8, p2U_8, p2V_8, p1_pitch, p2_pitch, width, height);
236 }
237
238 // instantiate
239 template void overlay_lighten_c<uint8_t>(BYTE *p1Y_8, BYTE *p1U_8, BYTE *p1V_8, const BYTE *p2Y_8, const BYTE *p2U_8, const BYTE *p2V_8, int p1_pitch, int p2_pitch, int width, int height);
240 template void overlay_lighten_c<uint16_t>(BYTE *p1Y_8, BYTE *p1U_8, BYTE *p1V_8, const BYTE *p2Y_8, const BYTE *p2U_8, const BYTE *p2V_8, int p1_pitch, int p2_pitch, int width, int height);
241