GCC Code Coverage Report


Directory: avs_core/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 72.5% 531 / 0 / 732
Functions: 74.4% 32 / 0 / 43
Branches: 38.4% 252 / 0 / 657

filters/overlay/blend_common.h
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 #ifndef __blend_common_h
38 #define __blend_common_h
39
40 #include <avs/types.h>
41 #include <avs/config.h>
42 #include <vector>
43
44 // Magic integer dividers for exact division by max_pixel_value (e.g. 255, 1023, …).
45 //
46 // Why /max_val instead of a power-of-two shift (÷256, ÷1024, …)?
47 //
48 // The per-pixel blend formula is: result = (a*(max-m) + b*m + half) / max
49 // where m ∈ [0..max] is the mask weight and max = (1<<bpp)-1.
50 //
51 // With the simpler power-of-two shift approach: (a*(range-m) + b*m) >> bpp,
52 // range = 1<<bpp = max+1 = 256 for 8-bit - the divisor is 256, not 255.
53 // That means m=255 maps to the fraction 255/256 ≈ 0.996, never to 1.0:
54 //
55 // m=255, b=255, a=0: (0*1 + 255*255) >> 8 = 65025 >> 8 = 254 is wrong
56 //
57 // The full-range endpoint is unreachable. Old Layer code worked around this
58 // by inflating the level: level = round(opacity * (max+1)) for the non-alpha
59 // path and level = round(opacity * (max+2)) for the alpha-aware path, so that
60 // a combined alpha*level product could reach the next power-of-two. This fixed
61 // the two extreme values (0 and max) but introduced asymmetry: intermediate
62 // mask values are unevenly distributed over the output range because 255 steps
63 // are mapped through a 256-wide divisor, leaving one "missing" step.
64 //
65 // Using /max (this approach) is exact at both endpoints and uniformly linear
66 // throughout: m=0 -> a, m=max -> b, every intermediate step is one equal part.
67 // The "magic" multiply+shift (compiler style constant division optimisation)
68 // makes the division as cheap as a shift at runtime.
69 struct MagicDiv {
70 uint32_t div;
71 uint8_t shift;
72 };
73
74 348 constexpr MagicDiv get_magic_div(int bits_per_pixel) {
75
5/6
✓ Branch 2 → 3 taken 179 times.
✓ Branch 2 → 4 taken 12 times.
✓ Branch 2 → 5 taken 12 times.
✓ Branch 2 → 6 taken 12 times.
✓ Branch 2 → 7 taken 133 times.
✗ Branch 2 → 8 not taken.
348 switch (bits_per_pixel) {
76 179 case 8: return { 0x8081, 7 }; // mulhi_epu16 path, different from word path
77 12 case 10: return { 0x80200803, 9 };
78 12 case 12: return { 0x80080081, 11 };
79 12 case 14: return { 0x80020009, 13 };
80 133 case 16: return { 0x80008001, 15 };
81 default: return { 0, 0 }; // unreachable
82 }
83 }
84
85 // Apply prefetched MagicDiv to value tmp.
86 // 8-bit (sizeof(pixel_t)==1) uses the mulhi_epu16 path (32-bit intermediate);
87 // wider uses the mul_epu32 path (64-bit intermediate)
88 // tmp is 0-255 for 8-bit pixels, and up to 65535 at 16-bit pixels.
89 template<typename pixel_t>
90 AVS_FORCEINLINE static int magic_div_rt(uint32_t tmp, const MagicDiv& magic) {
91 if constexpr (sizeof(pixel_t) == 1)
92 5562 return (int)(((uint32_t)tmp * magic.div) >> (16 + magic.shift));
93 else
94 10486 return (int)(((uint64_t)tmp * magic.div) >> (32 + magic.shift));
95 }
96
97 // ============================================================
98 // Chroma placement mask support
99 // Shared by Overlay and Layer blend paths.
100 // MASK444: mask is already at the plane's resolution (1:1).
101 // Other modes: mask is at luma resolution; values are averaged per placement
102 // before blending chroma planes.
103 // ============================================================
104
105 enum MaskMode {
106 MASK411,
107 MASK420,
108 MASK420_MPEG2,
109 MASK420_TOPLEFT, // co-sited H+V (HEVC/AV1 default): point-sample top-left luma only
110 MASK422,
111 MASK422_MPEG2,
112 MASK422_TOPLEFT, // co-sited H (same as MPEG-2): point-sample left luma only (faster, some aliasing)
113 MASK444
114 };
115
116 // Chroma placement constants — shared by Overlay and Layer.
117 // PLACEMENT_MPEG2 (0): co-sited H, centred V (H.262/MPEG-2, H.264 default; triangle filter)
118 // PLACEMENT_MPEG1 (1): centred H+V (MPEG-1 / JPEG; box filter)
119 // PLACEMENT_TOPLEFT (2): co-sited H+V (HEVC/AV1 default; point sample, faster)
120 enum { PLACEMENT_MPEG2 = 0, PLACEMENT_MPEG1 = 1, PLACEMENT_TOPLEFT = 2 };
121
122 // Compute the effective mask value at luma position x for a single chroma pixel,
123 // according to chroma subsampling placement.
124 // right_value: in/out sliding-window state, used only for MPEG2 modes.
125 template<MaskMode maskMode, typename pixel_t>
126 AVS_FORCEINLINE static pixel_t calculate_effective_mask(
127 const pixel_t* ptr,
128 int x,
129 int pitch,
130 int& right_value // in/out for MPEG2 sliding window modes; int to avoid truncation of 2-pixel sums
131 ) {
132 if constexpr (maskMode == MASK444) {
133 // +------+
134 // | 1.0 |
135 // +------+
136 return ptr[x];
137 }
138 else if constexpr (maskMode == MASK411) {
139 // +------+------+------+------+
140 // | 0.25 | 0.25 | 0.25 | 0.25 |
141 // +------+------+------+------+
142 return (ptr[x * 4] + ptr[x * 4 + 1] + ptr[x * 4 + 2] + ptr[x * 4 + 3] + 2) >> 2;
143 }
144 else if constexpr (maskMode == MASK420) {
145 // +------+------+
146 // | 0.25 | 0.25 |
147 // |------+------|
148 // | 0.25 | 0.25 |
149 // +------+------+
150 2620 const int upper = ptr[x * 2] + ptr[x * 2 + 1];
151 2620 const int lower = ptr[x * 2 + pitch] + ptr[x * 2 + 1 + pitch];
152 2620 return (upper + lower + 2) >> 2;
153 }
154 else if constexpr (maskMode == MASK420_MPEG2) {
155 // ------+------+-------+
156 // 0.125 | 0.25 | 0.125 |
157 // ------|------+-------|
158 // 0.125 | 0.25 | 0.125 |
159 // ------+------+-------+
160 842 int left = right_value;
161 842 const int mid = ptr[x * 2] + ptr[x * 2 + pitch];
162 842 right_value = ptr[x * 2 + 1] + ptr[x * 2 + 1 + pitch];
163 842 return (left + 2 * mid + right_value + 4) >> 3;
164 }
165 else if constexpr (maskMode == MASK420_TOPLEFT) {
166 // +------+
167 // | 1.0 | top-left co-sited (HEVC/AV1): point-sample top row only
168 // +------+
169 // (bottom row ignored)
170 520 return ptr[x * 2];
171 }
172 else if constexpr (maskMode == MASK422) {
173 // +------+------+
174 // | 0.5 | 0.5 |
175 // +------+------+
176 2260 return (ptr[x * 2] + ptr[x * 2 + 1] + 1) >> 1;
177 }
178 else if constexpr (maskMode == MASK422_MPEG2) {
179 // ------+------+-------+
180 // 0.25 | 0.5 | 0.25 |
181 // ------+------+-------+
182 520 int left = right_value;
183 520 const int mid = ptr[x * 2];
184 520 right_value = ptr[x * 2 + 1];
185 520 return (left + 2 * mid + right_value + 2) >> 2;
186 }
187 else if constexpr (maskMode == MASK422_TOPLEFT) {
188 // +------+
189 // | 1.0 | left co-sited (same H as MPEG-2): point-sample only
190 // +------+
191 520 return ptr[x * 2];
192 }
193 }
194
195 // Float version of calculate_effective_mask.
196 template<MaskMode maskMode>
197 AVS_FORCEINLINE static float calculate_effective_mask_f(
198 const float* ptr,
199 int x,
200 int pitch,
201 float& right_value // in/out for MPEG2 sliding window modes
202 ) {
203 if constexpr (maskMode == MASK444) {
204 return ptr[x];
205 }
206 else if constexpr (maskMode == MASK411) {
207 return (ptr[x * 4] + ptr[x * 4 + 1] + ptr[x * 4 + 2] + ptr[x * 4 + 3]) * 0.25f;
208 }
209 else if constexpr (maskMode == MASK420) {
210 680 return (ptr[x * 2] + ptr[x * 2 + 1] + ptr[x * 2 + pitch] + ptr[x * 2 + 1 + pitch]) * 0.25f;
211 }
212 else if constexpr (maskMode == MASK420_MPEG2) {
213 float left = right_value;
214 const float mid = ptr[x * 2] + ptr[x * 2 + pitch];
215 right_value = ptr[x * 2 + 1] + ptr[x * 2 + 1 + pitch];
216 return (left + 2.0f * mid + right_value) * 0.125f;
217 }
218 else if constexpr (maskMode == MASK420_TOPLEFT) {
219 return ptr[x * 2];
220 }
221 else if constexpr (maskMode == MASK422) {
222 680 return (ptr[x * 2] + ptr[x * 2 + 1]) * 0.5f;
223 }
224 else if constexpr (maskMode == MASK422_MPEG2) {
225 float left = right_value;
226 const float mid = ptr[x * 2];
227 right_value = ptr[x * 2 + 1];
228 return (left + 2.0f * mid + right_value) * 0.25f;
229 }
230 else if constexpr (maskMode == MASK422_TOPLEFT) {
231 return ptr[x * 2];
232 }
233 }
234
235 // Precalculate a complete row of effective mask values.
236 // integer 8-16 bits version.
237 //
238 // full_opacity == true (default): opacity is 1.0 — mask used as-is.
239 // MASK444: returns original maskp pointer directly (no copy, no buffer needed).
240 // Others: fills buffer with spatial averages and returns buffer.data().
241 //
242 // full_opacity == false: opacity < 1.0 — bake (avg * opacity_i + half) / max into the buffer.
243 // MASK444: copies maskp row scaled by opacity into buffer, returns buffer.data().
244 // Others: fills buffer with spatial-averaged-and-opacity-scaled values.
245 // Caller must have allocated effective_mask_buffer (even for MASK444).
246 //
247 // mask_pitch is in pixels (caller has divided by sizeof(pixel_t)).
248 // opacity_i, half, magic are ignored when full_opacity == true.
249 template<MaskMode maskMode, typename pixel_t, bool full_opacity = true>
250 AVS_FORCEINLINE static const pixel_t* prepare_effective_mask_for_row(
251 const pixel_t* maskp,
252 int mask_pitch,
253 int width,
254 std::vector<pixel_t>& effective_mask_buffer,
255 int opacity_i = 0,
256 int half = 0,
257 MagicDiv magic = {}
258 ) {
259 if constexpr (maskMode == MASK444) {
260 if constexpr (full_opacity) {
261 126 return maskp;
262 } else {
263
10/10
✓ Branch 12 → 8 taken 910 times.
✓ Branch 12 → 13 taken 30 times.
✓ Branch 29 → 25 taken 380 times.
✓ Branch 29 → 30 taken 20 times.
✓ Branch 42 → 38 taken 380 times.
✓ Branch 42 → 43 taken 20 times.
✓ Branch 55 → 51 taken 380 times.
✓ Branch 55 → 56 taken 20 times.
✓ Branch 68 → 64 taken 470 times.
✓ Branch 68 → 69 taken 30 times.
2640 for (int x = 0; x < width; ++x)
264 2520 effective_mask_buffer[x] = static_cast<pixel_t>(
265 5040 magic_div_rt<pixel_t>((uint32_t)maskp[x] * (uint32_t)opacity_i + (uint32_t)half, magic));
266 120 return effective_mask_buffer.data();
267 }
268 }
269 else {
270 454 int mask_right = 0; // int: MASK420_MPEG2 stores a 2-pixel sum (up to 510 for 8-bit), pixel_t would truncate
271 if constexpr (maskMode == MASK420_MPEG2)
272 54 mask_right = maskp[0] + maskp[0 + mask_pitch];
273 else if constexpr (maskMode == MASK422_MPEG2)
274 40 mask_right = maskp[0];
275
276
8/49
✗ Branch 8 → 4 not taken.
✗ Branch 8 → 9 not taken.
✗ Branch 10 → 4 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 11 → 7 not taken.
✗ Branch 11 → 12 not taken.
✓ Branch 12 → 8 taken 1700 times.
✓ Branch 12 → 13 taken 100 times.
✗ Branch 13 → 9 not taken.
✗ Branch 13 → 14 not taken.
✓ Branch 14 → 8 taken 2762 times.
✗ Branch 14 → 10 not taken.
✓ Branch 14 → 15 taken 134 times.
✗ Branch 18 → 14 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 22 → 16 not taken.
✗ Branch 22 → 18 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 23 → 19 not taken.
✗ Branch 23 → 24 not taken.
✗ Branch 28 → 24 not taken.
✗ Branch 28 → 29 not taken.
✗ Branch 30 → 26 not taken.
✗ Branch 30 → 31 not taken.
✗ Branch 34 → 28 not taken.
✗ Branch 34 → 35 not taken.
✗ Branch 38 → 34 not taken.
✗ Branch 38 → 39 not taken.
✗ Branch 44 → 40 not taken.
✗ Branch 44 → 45 not taken.
✗ Branch 46 → 40 not taken.
✗ Branch 46 → 47 not taken.
✗ Branch 48 → 44 not taken.
✗ Branch 48 → 49 not taken.
✗ Branch 50 → 44 not taken.
✗ Branch 50 → 51 not taken.
✗ Branch 58 → 52 not taken.
✗ Branch 58 → 54 not taken.
✗ Branch 58 → 59 not taken.
✗ Branch 66 → 60 not taken.
✗ Branch 66 → 67 not taken.
✗ Branch 68 → 64 not taken.
✗ Branch 68 → 69 not taken.
✗ Branch 70 → 64 not taken.
✗ Branch 70 → 71 not taken.
✓ Branch 72 → 68 taken 1220 times.
✓ Branch 72 → 73 taken 100 times.
✓ Branch 82 → 76 taken 1600 times.
✓ Branch 82 → 83 taken 120 times.
7736 for (int x = 0; x < width; ++x) {
277 7282 const pixel_t avg = (pixel_t)calculate_effective_mask<maskMode>(maskp, x, mask_pitch, mask_right);
278 if constexpr (full_opacity)
279 2920 effective_mask_buffer[x] = avg;
280 else
281 4362 effective_mask_buffer[x] = static_cast<pixel_t>(
282 8724 magic_div_rt<pixel_t>((uint32_t)avg * (uint32_t)opacity_i + (uint32_t)half, magic));
283 }
284 908 return effective_mask_buffer.data();
285 }
286 }
287
288
289 // Float version of prepare_effective_mask_for_row.
290 // full_opacity == true (default): returns maskp for MASK444; spatial avg for others.
291 // full_opacity == false: bakes opacity_f into every output element.
292 // MASK444: copies row scaled by opacity_f; buffer must be allocated by caller.
293 // mask_pitch is in floats (caller has divided by sizeof(float)).
294 // opacity_f is ignored when full_opacity == true.
295 template<MaskMode maskMode, bool full_opacity = true>
296 AVS_FORCEINLINE static const float* prepare_effective_mask_for_row_float_c(
297 const float* maskp,
298 int mask_pitch,
299 int width,
300 std::vector<float>& effective_mask_buffer,
301 float opacity_f = 1.0f
302 ) {
303 if constexpr (maskMode == MASK444) {
304 if constexpr (full_opacity) {
305 20 return maskp;
306 } else {
307
2/2
✓ Branch 19 → 17 taken 260 times.
✓ Branch 19 → 20 taken 20 times.
280 for (int x = 0; x < width; ++x)
308 260 effective_mask_buffer[x] = maskp[x] * opacity_f;
309 20 return effective_mask_buffer.data();
310 }
311 }
312 else {
313 80 float mask_right = 0.0f;
314 if constexpr (maskMode == MASK420_MPEG2)
315 mask_right = maskp[0] + maskp[0 + mask_pitch];
316 else if constexpr (maskMode == MASK422_MPEG2)
317 mask_right = maskp[0];
318
319
4/28
✗ Branch 8 → 4 not taken.
✗ Branch 8 → 9 not taken.
✗ Branch 10 → 6 not taken.
✗ Branch 10 → 11 not taken.
✓ Branch 11 → 7 taken 680 times.
✓ Branch 11 → 12 taken 40 times.
✗ Branch 12 → 8 not taken.
✗ Branch 12 → 13 not taken.
✗ Branch 13 → 9 not taken.
✗ Branch 13 → 14 not taken.
✗ Branch 18 → 14 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 21 → 17 not taken.
✗ Branch 21 → 22 not taken.
✗ Branch 22 → 18 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 28 → 24 not taken.
✗ Branch 28 → 29 not taken.
✓ Branch 32 → 28 taken 680 times.
✓ Branch 32 → 33 taken 40 times.
✗ Branch 38 → 34 not taken.
✗ Branch 38 → 39 not taken.
✗ Branch 48 → 44 not taken.
✗ Branch 48 → 49 not taken.
✗ Branch 58 → 54 not taken.
✗ Branch 58 → 59 not taken.
✗ Branch 68 → 64 not taken.
✗ Branch 68 → 69 not taken.
1440 for (int x = 0; x < width; ++x) {
320 1360 const float avg = calculate_effective_mask_f<maskMode>(maskp, x, mask_pitch, mask_right);
321 if constexpr (full_opacity)
322 680 effective_mask_buffer[x] = avg;
323 else
324 680 effective_mask_buffer[x] = avg * opacity_f;
325 }
326 160 return effective_mask_buffer.data();
327 }
328 }
329
330 // ============================================================
331 // masked_merge inline template implementations
332 // Templated on maskMode so Layer (luma-res mask, placement-aware) and
333 // Overlay (mask already at plane resolution, MASK444) share the same code.
334 //
335 // For MASK420/MASK420_MPEG2/MASK420_TOPLEFT the mask pointer advances 2 luma rows per output row.
336 // ============================================================
337 // ---------------------------------------------------------------------------
338 // 8-bit row — mask already has opacity baked in by rowprep.
339 // 32-wide 16-bit mulhi arithmetic (fast, overflow-safe).
340 // ---------------------------------------------------------------------------
341 294 static void blend8_masked_c_row(
342 uint8_t* p1, const uint8_t* p2, const uint8_t* mask,
343 int width)
344 {
345 294 constexpr uint32_t half = 127u;
346 294 constexpr uint32_t max_val = 255u;
347
348 294 int x = 0;
349
2/2
✓ Branch 4 → 3 taken 6282 times.
✓ Branch 4 → 5 taken 294 times.
6576 for (; x < width; ++x) {
350 6282 const uint32_t ms = mask[x];
351 6282 const uint32_t a = p1[x], b_v = p2[x];
352 6282 const uint32_t tr = a * (max_val - ms) + b_v * ms + half;
353 6282 p1[x] = (uint8_t)((tr * 0x8081u) >> 23);
354 }
355 294 }
356
357 // ---------------------------------------------------------------------------
358 // 16-bit row (10, 12, 14, 16 bits) — mask already has opacity baked in.
359 // 32-bit arithmetic, 8 pixels per step.
360 // ---------------------------------------------------------------------------
361 template<int bits_per_pixel>
362 400 static void blend16_masked_c_row(
363 uint16_t* p1, const uint16_t* p2, const uint16_t* mask,
364 int width)
365 {
366 400 constexpr MagicDiv m_div = get_magic_div(bits_per_pixel);
367 400 constexpr uint32_t max_val = (1u << bits_per_pixel) - 1;
368 400 constexpr uint32_t half = max_val / 2;
369
370 400 int x = 0;
371
8/8
void blend16_masked_c_row<10>(unsigned short*, unsigned short const*, unsigned short const*, int):
✓ Branch 6 → 3 taken 760 times.
✓ Branch 6 → 7 taken 40 times.
void blend16_masked_c_row<12>(unsigned short*, unsigned short const*, unsigned short const*, int):
✓ Branch 6 → 3 taken 760 times.
✓ Branch 6 → 7 taken 40 times.
void blend16_masked_c_row<14>(unsigned short*, unsigned short const*, unsigned short const*, int):
✓ Branch 6 → 3 taken 760 times.
✓ Branch 6 → 7 taken 40 times.
void blend16_masked_c_row<16>(unsigned short*, unsigned short const*, unsigned short const*, int):
✓ Branch 6 → 3 taken 3760 times.
✓ Branch 6 → 7 taken 280 times.
6440 for (; x < width; ++x) {
372 6040 const uint32_t ms = mask[x];
373 6040 const uint32_t a = p1[x];
374 12080 p1[x] = (uint16_t)magic_div_rt<uint16_t>(a * (max_val - ms) + (uint32_t)p2[x] * ms + half, m_div);
375 }
376 400 }
377
378 // ---------------------------------------------------------------------------
379 // float row — mask already has opacity baked in (range 0.0 to 1.0).
380 // Linear interpolation: p1[x] = p1[x] * (1.0f - mask[x]) + p2[x] * mask[x]
381 // 8 pixels per step.
382 // ---------------------------------------------------------------------------
383 120 static void blend_masked_float_c_row(
384 float* p1, const float* p2, const float* mask, int width)
385 {
386 120 int x = 0;
387
388 // Scalar tail
389
2/2
✓ Branch 4 → 3 taken 1880 times.
✓ Branch 4 → 5 taken 120 times.
2000 for (; x < width; ++x) {
390 1880 const float m = mask[x];
391 1880 const float a = p1[x];
392 1880 const float b = p2[x];
393 1880 p1[x] = a + m * (b - a);
394 }
395 120 }
396
397
398 // Inner loop: opacity already baked into effective_mask_ptr by rowprep.
399 template<MaskMode maskMode, bool full_opacity>
400 138 static void masked_merge_impl_c_inner(
401 BYTE* p1, const BYTE* p2, const BYTE* mask,
402 int p1_pitch, int p2_pitch, int mask_pitch,
403 int width, int height, int opacity, int bits_per_pixel)
404 {
405 // bits_per_pixel == 8 -> pixel_t is uint8_t, max_pixel_value is 255, magic_div_rt uses mulhi_epu16 path.
406 // bits_per_pixel >8 and <= 16 -> pixel_t is uint16_t, max_pixel_value
407
408 138 const MagicDiv mag = get_magic_div(bits_per_pixel);
409 138 const int max_val = (1 << bits_per_pixel) - 1;
410 138 const int half = max_val / 2;
411
412
28/32
void masked_merge_impl_c_inner<(MaskMode)0, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 23 not taken.
void masked_merge_impl_c_inner<(MaskMode)0, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 21 not taken.
void masked_merge_impl_c_inner<(MaskMode)1, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 3 → 4 taken 10 times.
✓ Branch 3 → 23 taken 6 times.
void masked_merge_impl_c_inner<(MaskMode)1, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 3 → 4 taken 6 times.
✓ Branch 3 → 21 taken 6 times.
void masked_merge_impl_c_inner<(MaskMode)2, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 3 → 4 taken 4 times.
✓ Branch 3 → 23 taken 2 times.
void masked_merge_impl_c_inner<(MaskMode)2, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 21 taken 2 times.
void masked_merge_impl_c_inner<(MaskMode)3, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 23 taken 2 times.
void masked_merge_impl_c_inner<(MaskMode)3, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 21 taken 2 times.
void masked_merge_impl_c_inner<(MaskMode)4, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 3 → 4 taken 6 times.
✓ Branch 3 → 23 taken 10 times.
void masked_merge_impl_c_inner<(MaskMode)4, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 3 → 4 taken 6 times.
✓ Branch 3 → 21 taken 6 times.
void masked_merge_impl_c_inner<(MaskMode)5, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 23 taken 2 times.
void masked_merge_impl_c_inner<(MaskMode)5, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 21 taken 2 times.
void masked_merge_impl_c_inner<(MaskMode)6, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 23 taken 2 times.
void masked_merge_impl_c_inner<(MaskMode)6, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 21 taken 2 times.
void masked_merge_impl_c_inner<(MaskMode)7, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 3 → 4 taken 6 times.
✓ Branch 3 → 20 taken 18 times.
void masked_merge_impl_c_inner<(MaskMode)7, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 3 → 4 taken 6 times.
✓ Branch 3 → 13 taken 18 times.
138 if (bits_per_pixel == 8) {
413 58 const uint8_t* maskp = reinterpret_cast<const uint8_t*>(mask);
414 58 const int mpx = mask_pitch;
415 58 const int mask_adv = (maskMode == MASK420 || maskMode == MASK420_MPEG2 || maskMode == MASK420_TOPLEFT) ? mpx * 2 : mpx;
416
417 58 std::vector<uint8_t> eff_buf;
418
13/30
void masked_merge_impl_c_inner<(MaskMode)0, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 93 not taken.
void masked_merge_impl_c_inner<(MaskMode)0, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 83 not taken.
void masked_merge_impl_c_inner<(MaskMode)1, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 5 → 6 taken 10 times.
✗ Branch 5 → 93 not taken.
void masked_merge_impl_c_inner<(MaskMode)1, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 5 → 6 taken 6 times.
✗ Branch 5 → 83 not taken.
void masked_merge_impl_c_inner<(MaskMode)2, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 5 → 6 taken 4 times.
✗ Branch 5 → 93 not taken.
void masked_merge_impl_c_inner<(MaskMode)2, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 5 → 6 taken 2 times.
✗ Branch 5 → 83 not taken.
void masked_merge_impl_c_inner<(MaskMode)3, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 5 → 6 taken 2 times.
✗ Branch 5 → 93 not taken.
void masked_merge_impl_c_inner<(MaskMode)3, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 5 → 6 taken 2 times.
✗ Branch 5 → 83 not taken.
void masked_merge_impl_c_inner<(MaskMode)4, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 5 → 6 taken 6 times.
✗ Branch 5 → 93 not taken.
void masked_merge_impl_c_inner<(MaskMode)4, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 5 → 6 taken 6 times.
✗ Branch 5 → 83 not taken.
void masked_merge_impl_c_inner<(MaskMode)5, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 5 → 6 taken 2 times.
✗ Branch 5 → 93 not taken.
void masked_merge_impl_c_inner<(MaskMode)5, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 5 → 6 taken 2 times.
✗ Branch 5 → 83 not taken.
void masked_merge_impl_c_inner<(MaskMode)6, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 5 → 6 taken 2 times.
✗ Branch 5 → 93 not taken.
void masked_merge_impl_c_inner<(MaskMode)6, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 5 → 6 taken 2 times.
✗ Branch 5 → 83 not taken.
void masked_merge_impl_c_inner<(MaskMode)7, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 5 → 6 taken 6 times.
✗ Branch 5 → 78 not taken.
52 if constexpr (maskMode != MASK444 || !full_opacity) eff_buf.resize(width);
419
420
28/32
void masked_merge_impl_c_inner<(MaskMode)0, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 20 → 7 not taken.
✗ Branch 20 → 21 not taken.
void masked_merge_impl_c_inner<(MaskMode)0, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 18 → 7 not taken.
✗ Branch 18 → 19 not taken.
void masked_merge_impl_c_inner<(MaskMode)1, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 20 → 7 taken 50 times.
✓ Branch 20 → 21 taken 10 times.
void masked_merge_impl_c_inner<(MaskMode)1, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 18 → 7 taken 30 times.
✓ Branch 18 → 19 taken 6 times.
void masked_merge_impl_c_inner<(MaskMode)2, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 20 → 7 taken 24 times.
✓ Branch 20 → 21 taken 4 times.
void masked_merge_impl_c_inner<(MaskMode)2, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 18 → 7 taken 10 times.
✓ Branch 18 → 19 taken 2 times.
void masked_merge_impl_c_inner<(MaskMode)3, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 20 → 7 taken 10 times.
✓ Branch 20 → 21 taken 2 times.
void masked_merge_impl_c_inner<(MaskMode)3, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 18 → 7 taken 10 times.
✓ Branch 18 → 19 taken 2 times.
void masked_merge_impl_c_inner<(MaskMode)4, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 20 → 7 taken 30 times.
✓ Branch 20 → 21 taken 6 times.
void masked_merge_impl_c_inner<(MaskMode)4, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 18 → 7 taken 30 times.
✓ Branch 18 → 19 taken 6 times.
void masked_merge_impl_c_inner<(MaskMode)5, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 20 → 7 taken 10 times.
✓ Branch 20 → 21 taken 2 times.
void masked_merge_impl_c_inner<(MaskMode)5, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 18 → 7 taken 10 times.
✓ Branch 18 → 19 taken 2 times.
void masked_merge_impl_c_inner<(MaskMode)6, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 20 → 7 taken 10 times.
✓ Branch 20 → 21 taken 2 times.
void masked_merge_impl_c_inner<(MaskMode)6, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 18 → 7 taken 10 times.
✓ Branch 18 → 19 taken 2 times.
void masked_merge_impl_c_inner<(MaskMode)7, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 17 → 7 taken 30 times.
✓ Branch 17 → 18 taken 6 times.
void masked_merge_impl_c_inner<(MaskMode)7, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 10 → 6 taken 30 times.
✓ Branch 10 → 11 taken 6 times.
352 for (int y = 0; y < height; y++) {
421 294 const uint8_t* eff = prepare_effective_mask_for_row<maskMode, uint8_t, full_opacity>(
422 maskp, mpx, width, eff_buf, opacity, half, mag);
423 294 blend8_masked_c_row(
424 reinterpret_cast<uint8_t*>(p1), reinterpret_cast<const uint8_t*>(p2), eff, width);
425 294 p1 += p1_pitch; p2 += p2_pitch; maskp += mask_adv;
426 }
427 58 return;
428 58 }
429
430 80 const uint16_t* maskp = reinterpret_cast<const uint16_t*>(mask);
431 80 const int mpx = mask_pitch / 2;
432 80 const int mask_adv = (maskMode == MASK420 || maskMode == MASK420_MPEG2 || maskMode == MASK420_TOPLEFT) ? mpx * 2 : mpx;
433
434 80 std::vector<uint16_t> eff_buf;
435
13/30
void masked_merge_impl_c_inner<(MaskMode)0, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 24 → 25 not taken.
✗ Branch 24 → 96 not taken.
void masked_merge_impl_c_inner<(MaskMode)0, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 22 → 23 not taken.
✗ Branch 22 → 86 not taken.
void masked_merge_impl_c_inner<(MaskMode)1, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 24 → 25 taken 6 times.
✗ Branch 24 → 96 not taken.
void masked_merge_impl_c_inner<(MaskMode)1, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 22 → 23 taken 6 times.
✗ Branch 22 → 86 not taken.
void masked_merge_impl_c_inner<(MaskMode)2, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 24 → 25 taken 2 times.
✗ Branch 24 → 96 not taken.
void masked_merge_impl_c_inner<(MaskMode)2, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 22 → 23 taken 2 times.
✗ Branch 22 → 86 not taken.
void masked_merge_impl_c_inner<(MaskMode)3, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 24 → 25 taken 2 times.
✗ Branch 24 → 96 not taken.
void masked_merge_impl_c_inner<(MaskMode)3, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 22 → 23 taken 2 times.
✗ Branch 22 → 86 not taken.
void masked_merge_impl_c_inner<(MaskMode)4, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 24 → 25 taken 10 times.
✗ Branch 24 → 96 not taken.
void masked_merge_impl_c_inner<(MaskMode)4, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 22 → 23 taken 6 times.
✗ Branch 22 → 86 not taken.
void masked_merge_impl_c_inner<(MaskMode)5, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 24 → 25 taken 2 times.
✗ Branch 24 → 96 not taken.
void masked_merge_impl_c_inner<(MaskMode)5, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 22 → 23 taken 2 times.
✗ Branch 22 → 86 not taken.
void masked_merge_impl_c_inner<(MaskMode)6, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 24 → 25 taken 2 times.
✗ Branch 24 → 96 not taken.
void masked_merge_impl_c_inner<(MaskMode)6, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 22 → 23 taken 2 times.
✗ Branch 22 → 86 not taken.
void masked_merge_impl_c_inner<(MaskMode)7, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 21 → 22 taken 18 times.
✗ Branch 21 → 81 not taken.
62 if constexpr (maskMode != MASK444 || !full_opacity) eff_buf.resize(width);
436
437 #define BLEND16_LOOP_C(bpp) \
438 for (int y = 0; y < height; y++) { \
439 const uint16_t* eff = prepare_effective_mask_for_row<maskMode, uint16_t, full_opacity>( \
440 maskp, mpx, width, eff_buf, opacity, half, mag); \
441 blend16_masked_c_row<bpp>( \
442 reinterpret_cast<uint16_t*>(p1), reinterpret_cast<const uint16_t*>(p2), eff, width); \
443 p1 += p1_pitch; p2 += p2_pitch; maskp += mask_adv; \
444 } break;
445
446
20/80
void masked_merge_impl_c_inner<(MaskMode)0, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 25 → 26 not taken.
✗ Branch 25 → 42 not taken.
✗ Branch 25 → 58 not taken.
✗ Branch 25 → 74 not taken.
✗ Branch 25 → 90 not taken.
void masked_merge_impl_c_inner<(MaskMode)0, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 23 → 24 not taken.
✗ Branch 23 → 38 not taken.
✗ Branch 23 → 52 not taken.
✗ Branch 23 → 66 not taken.
✗ Branch 23 → 80 not taken.
void masked_merge_impl_c_inner<(MaskMode)1, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 25 → 26 not taken.
✗ Branch 25 → 42 not taken.
✗ Branch 25 → 58 not taken.
✓ Branch 25 → 74 taken 6 times.
✗ Branch 25 → 90 not taken.
void masked_merge_impl_c_inner<(MaskMode)1, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 23 → 24 not taken.
✗ Branch 23 → 38 not taken.
✗ Branch 23 → 52 not taken.
✓ Branch 23 → 66 taken 6 times.
✗ Branch 23 → 80 not taken.
void masked_merge_impl_c_inner<(MaskMode)2, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 25 → 26 not taken.
✗ Branch 25 → 42 not taken.
✗ Branch 25 → 58 not taken.
✓ Branch 25 → 74 taken 2 times.
✗ Branch 25 → 90 not taken.
void masked_merge_impl_c_inner<(MaskMode)2, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 23 → 24 not taken.
✗ Branch 23 → 38 not taken.
✗ Branch 23 → 52 not taken.
✓ Branch 23 → 66 taken 2 times.
✗ Branch 23 → 80 not taken.
void masked_merge_impl_c_inner<(MaskMode)3, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 25 → 26 not taken.
✗ Branch 25 → 42 not taken.
✗ Branch 25 → 58 not taken.
✓ Branch 25 → 74 taken 2 times.
✗ Branch 25 → 90 not taken.
void masked_merge_impl_c_inner<(MaskMode)3, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 23 → 24 not taken.
✗ Branch 23 → 38 not taken.
✗ Branch 23 → 52 not taken.
✓ Branch 23 → 66 taken 2 times.
✗ Branch 23 → 80 not taken.
void masked_merge_impl_c_inner<(MaskMode)4, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 25 → 26 not taken.
✗ Branch 25 → 42 not taken.
✗ Branch 25 → 58 not taken.
✓ Branch 25 → 74 taken 10 times.
✗ Branch 25 → 90 not taken.
void masked_merge_impl_c_inner<(MaskMode)4, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 23 → 24 not taken.
✗ Branch 23 → 38 not taken.
✗ Branch 23 → 52 not taken.
✓ Branch 23 → 66 taken 6 times.
✗ Branch 23 → 80 not taken.
void masked_merge_impl_c_inner<(MaskMode)5, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 25 → 26 not taken.
✗ Branch 25 → 42 not taken.
✗ Branch 25 → 58 not taken.
✓ Branch 25 → 74 taken 2 times.
✗ Branch 25 → 90 not taken.
void masked_merge_impl_c_inner<(MaskMode)5, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 23 → 24 not taken.
✗ Branch 23 → 38 not taken.
✗ Branch 23 → 52 not taken.
✓ Branch 23 → 66 taken 2 times.
✗ Branch 23 → 80 not taken.
void masked_merge_impl_c_inner<(MaskMode)6, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 25 → 26 not taken.
✗ Branch 25 → 42 not taken.
✗ Branch 25 → 58 not taken.
✓ Branch 25 → 74 taken 2 times.
✗ Branch 25 → 90 not taken.
void masked_merge_impl_c_inner<(MaskMode)6, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 23 → 24 not taken.
✗ Branch 23 → 38 not taken.
✗ Branch 23 → 52 not taken.
✓ Branch 23 → 66 taken 2 times.
✗ Branch 23 → 80 not taken.
void masked_merge_impl_c_inner<(MaskMode)7, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 22 → 23 taken 4 times.
✓ Branch 22 → 36 taken 4 times.
✓ Branch 22 → 49 taken 4 times.
✓ Branch 22 → 62 taken 6 times.
✗ Branch 22 → 75 not taken.
void masked_merge_impl_c_inner<(MaskMode)7, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 14 → 15 taken 4 times.
✓ Branch 14 → 22 taken 4 times.
✓ Branch 14 → 29 taken 4 times.
✓ Branch 14 → 36 taken 6 times.
✗ Branch 14 → 43 not taken.
80 switch (bits_per_pixel) {
447
6/64
void masked_merge_impl_c_inner<(MaskMode)0, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 38 → 39 not taken.
✗ Branch 38 → 96 not taken.
✗ Branch 40 → 27 not taken.
✗ Branch 40 → 41 not taken.
void masked_merge_impl_c_inner<(MaskMode)0, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 34 → 35 not taken.
✗ Branch 34 → 86 not taken.
✗ Branch 36 → 25 not taken.
✗ Branch 36 → 37 not taken.
void masked_merge_impl_c_inner<(MaskMode)1, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 38 → 39 not taken.
✗ Branch 38 → 96 not taken.
✗ Branch 40 → 27 not taken.
✗ Branch 40 → 41 not taken.
void masked_merge_impl_c_inner<(MaskMode)1, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 34 → 35 not taken.
✗ Branch 34 → 86 not taken.
✗ Branch 36 → 25 not taken.
✗ Branch 36 → 37 not taken.
void masked_merge_impl_c_inner<(MaskMode)2, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 38 → 39 not taken.
✗ Branch 38 → 96 not taken.
✗ Branch 40 → 27 not taken.
✗ Branch 40 → 41 not taken.
void masked_merge_impl_c_inner<(MaskMode)2, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 34 → 35 not taken.
✗ Branch 34 → 86 not taken.
✗ Branch 36 → 25 not taken.
✗ Branch 36 → 37 not taken.
void masked_merge_impl_c_inner<(MaskMode)3, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 38 → 39 not taken.
✗ Branch 38 → 96 not taken.
✗ Branch 40 → 27 not taken.
✗ Branch 40 → 41 not taken.
void masked_merge_impl_c_inner<(MaskMode)3, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 34 → 35 not taken.
✗ Branch 34 → 86 not taken.
✗ Branch 36 → 25 not taken.
✗ Branch 36 → 37 not taken.
void masked_merge_impl_c_inner<(MaskMode)4, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 38 → 39 not taken.
✗ Branch 38 → 96 not taken.
✗ Branch 40 → 27 not taken.
✗ Branch 40 → 41 not taken.
void masked_merge_impl_c_inner<(MaskMode)4, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 34 → 35 not taken.
✗ Branch 34 → 86 not taken.
✗ Branch 36 → 25 not taken.
✗ Branch 36 → 37 not taken.
void masked_merge_impl_c_inner<(MaskMode)5, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 38 → 39 not taken.
✗ Branch 38 → 96 not taken.
✗ Branch 40 → 27 not taken.
✗ Branch 40 → 41 not taken.
void masked_merge_impl_c_inner<(MaskMode)5, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 34 → 35 not taken.
✗ Branch 34 → 86 not taken.
✗ Branch 36 → 25 not taken.
✗ Branch 36 → 37 not taken.
void masked_merge_impl_c_inner<(MaskMode)6, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 38 → 39 not taken.
✗ Branch 38 → 96 not taken.
✗ Branch 40 → 27 not taken.
✗ Branch 40 → 41 not taken.
void masked_merge_impl_c_inner<(MaskMode)6, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 34 → 35 not taken.
✗ Branch 34 → 86 not taken.
✗ Branch 36 → 25 not taken.
✗ Branch 36 → 37 not taken.
void masked_merge_impl_c_inner<(MaskMode)7, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 32 → 33 taken 20 times.
✗ Branch 32 → 81 not taken.
✓ Branch 34 → 24 taken 20 times.
✓ Branch 34 → 35 taken 4 times.
void masked_merge_impl_c_inner<(MaskMode)7, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 18 → 19 taken 20 times.
✗ Branch 18 → 46 not taken.
✓ Branch 20 → 16 taken 20 times.
✓ Branch 20 → 21 taken 4 times.
48 case 10: BLEND16_LOOP_C(10)
448
6/64
void masked_merge_impl_c_inner<(MaskMode)0, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 54 → 55 not taken.
✗ Branch 54 → 96 not taken.
✗ Branch 56 → 43 not taken.
✗ Branch 56 → 57 not taken.
void masked_merge_impl_c_inner<(MaskMode)0, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 48 → 49 not taken.
✗ Branch 48 → 86 not taken.
✗ Branch 50 → 39 not taken.
✗ Branch 50 → 51 not taken.
void masked_merge_impl_c_inner<(MaskMode)1, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 54 → 55 not taken.
✗ Branch 54 → 96 not taken.
✗ Branch 56 → 43 not taken.
✗ Branch 56 → 57 not taken.
void masked_merge_impl_c_inner<(MaskMode)1, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 48 → 49 not taken.
✗ Branch 48 → 86 not taken.
✗ Branch 50 → 39 not taken.
✗ Branch 50 → 51 not taken.
void masked_merge_impl_c_inner<(MaskMode)2, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 54 → 55 not taken.
✗ Branch 54 → 96 not taken.
✗ Branch 56 → 43 not taken.
✗ Branch 56 → 57 not taken.
void masked_merge_impl_c_inner<(MaskMode)2, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 48 → 49 not taken.
✗ Branch 48 → 86 not taken.
✗ Branch 50 → 39 not taken.
✗ Branch 50 → 51 not taken.
void masked_merge_impl_c_inner<(MaskMode)3, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 54 → 55 not taken.
✗ Branch 54 → 96 not taken.
✗ Branch 56 → 43 not taken.
✗ Branch 56 → 57 not taken.
void masked_merge_impl_c_inner<(MaskMode)3, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 48 → 49 not taken.
✗ Branch 48 → 86 not taken.
✗ Branch 50 → 39 not taken.
✗ Branch 50 → 51 not taken.
void masked_merge_impl_c_inner<(MaskMode)4, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 54 → 55 not taken.
✗ Branch 54 → 96 not taken.
✗ Branch 56 → 43 not taken.
✗ Branch 56 → 57 not taken.
void masked_merge_impl_c_inner<(MaskMode)4, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 48 → 49 not taken.
✗ Branch 48 → 86 not taken.
✗ Branch 50 → 39 not taken.
✗ Branch 50 → 51 not taken.
void masked_merge_impl_c_inner<(MaskMode)5, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 54 → 55 not taken.
✗ Branch 54 → 96 not taken.
✗ Branch 56 → 43 not taken.
✗ Branch 56 → 57 not taken.
void masked_merge_impl_c_inner<(MaskMode)5, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 48 → 49 not taken.
✗ Branch 48 → 86 not taken.
✗ Branch 50 → 39 not taken.
✗ Branch 50 → 51 not taken.
void masked_merge_impl_c_inner<(MaskMode)6, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 54 → 55 not taken.
✗ Branch 54 → 96 not taken.
✗ Branch 56 → 43 not taken.
✗ Branch 56 → 57 not taken.
void masked_merge_impl_c_inner<(MaskMode)6, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 48 → 49 not taken.
✗ Branch 48 → 86 not taken.
✗ Branch 50 → 39 not taken.
✗ Branch 50 → 51 not taken.
void masked_merge_impl_c_inner<(MaskMode)7, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 45 → 46 taken 20 times.
✗ Branch 45 → 81 not taken.
✓ Branch 47 → 37 taken 20 times.
✓ Branch 47 → 48 taken 4 times.
void masked_merge_impl_c_inner<(MaskMode)7, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 25 → 26 taken 20 times.
✗ Branch 25 → 46 not taken.
✓ Branch 27 → 23 taken 20 times.
✓ Branch 27 → 28 taken 4 times.
48 case 12: BLEND16_LOOP_C(12)
449
6/64
void masked_merge_impl_c_inner<(MaskMode)0, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 70 → 71 not taken.
✗ Branch 70 → 96 not taken.
✗ Branch 72 → 59 not taken.
✗ Branch 72 → 73 not taken.
void masked_merge_impl_c_inner<(MaskMode)0, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 62 → 63 not taken.
✗ Branch 62 → 86 not taken.
✗ Branch 64 → 53 not taken.
✗ Branch 64 → 65 not taken.
void masked_merge_impl_c_inner<(MaskMode)1, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 70 → 71 not taken.
✗ Branch 70 → 96 not taken.
✗ Branch 72 → 59 not taken.
✗ Branch 72 → 73 not taken.
void masked_merge_impl_c_inner<(MaskMode)1, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 62 → 63 not taken.
✗ Branch 62 → 86 not taken.
✗ Branch 64 → 53 not taken.
✗ Branch 64 → 65 not taken.
void masked_merge_impl_c_inner<(MaskMode)2, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 70 → 71 not taken.
✗ Branch 70 → 96 not taken.
✗ Branch 72 → 59 not taken.
✗ Branch 72 → 73 not taken.
void masked_merge_impl_c_inner<(MaskMode)2, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 62 → 63 not taken.
✗ Branch 62 → 86 not taken.
✗ Branch 64 → 53 not taken.
✗ Branch 64 → 65 not taken.
void masked_merge_impl_c_inner<(MaskMode)3, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 70 → 71 not taken.
✗ Branch 70 → 96 not taken.
✗ Branch 72 → 59 not taken.
✗ Branch 72 → 73 not taken.
void masked_merge_impl_c_inner<(MaskMode)3, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 62 → 63 not taken.
✗ Branch 62 → 86 not taken.
✗ Branch 64 → 53 not taken.
✗ Branch 64 → 65 not taken.
void masked_merge_impl_c_inner<(MaskMode)4, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 70 → 71 not taken.
✗ Branch 70 → 96 not taken.
✗ Branch 72 → 59 not taken.
✗ Branch 72 → 73 not taken.
void masked_merge_impl_c_inner<(MaskMode)4, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 62 → 63 not taken.
✗ Branch 62 → 86 not taken.
✗ Branch 64 → 53 not taken.
✗ Branch 64 → 65 not taken.
void masked_merge_impl_c_inner<(MaskMode)5, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 70 → 71 not taken.
✗ Branch 70 → 96 not taken.
✗ Branch 72 → 59 not taken.
✗ Branch 72 → 73 not taken.
void masked_merge_impl_c_inner<(MaskMode)5, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 62 → 63 not taken.
✗ Branch 62 → 86 not taken.
✗ Branch 64 → 53 not taken.
✗ Branch 64 → 65 not taken.
void masked_merge_impl_c_inner<(MaskMode)6, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 70 → 71 not taken.
✗ Branch 70 → 96 not taken.
✗ Branch 72 → 59 not taken.
✗ Branch 72 → 73 not taken.
void masked_merge_impl_c_inner<(MaskMode)6, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 62 → 63 not taken.
✗ Branch 62 → 86 not taken.
✗ Branch 64 → 53 not taken.
✗ Branch 64 → 65 not taken.
void masked_merge_impl_c_inner<(MaskMode)7, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 58 → 59 taken 20 times.
✗ Branch 58 → 81 not taken.
✓ Branch 60 → 50 taken 20 times.
✓ Branch 60 → 61 taken 4 times.
void masked_merge_impl_c_inner<(MaskMode)7, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 32 → 33 taken 20 times.
✗ Branch 32 → 46 not taken.
✓ Branch 34 → 30 taken 20 times.
✓ Branch 34 → 35 taken 4 times.
48 case 14: BLEND16_LOOP_C(14)
450
42/64
void masked_merge_impl_c_inner<(MaskMode)0, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 86 → 87 not taken.
✗ Branch 86 → 96 not taken.
✗ Branch 88 → 75 not taken.
✗ Branch 88 → 89 not taken.
void masked_merge_impl_c_inner<(MaskMode)0, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 76 → 77 not taken.
✗ Branch 76 → 86 not taken.
✗ Branch 78 → 67 not taken.
✗ Branch 78 → 79 not taken.
void masked_merge_impl_c_inner<(MaskMode)1, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 86 → 87 taken 30 times.
✗ Branch 86 → 96 not taken.
✓ Branch 88 → 75 taken 30 times.
✓ Branch 88 → 89 taken 6 times.
void masked_merge_impl_c_inner<(MaskMode)1, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 76 → 77 taken 30 times.
✗ Branch 76 → 86 not taken.
✓ Branch 78 → 67 taken 30 times.
✓ Branch 78 → 79 taken 6 times.
void masked_merge_impl_c_inner<(MaskMode)2, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 86 → 87 taken 10 times.
✗ Branch 86 → 96 not taken.
✓ Branch 88 → 75 taken 10 times.
✓ Branch 88 → 89 taken 2 times.
void masked_merge_impl_c_inner<(MaskMode)2, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 76 → 77 taken 10 times.
✗ Branch 76 → 86 not taken.
✓ Branch 78 → 67 taken 10 times.
✓ Branch 78 → 79 taken 2 times.
void masked_merge_impl_c_inner<(MaskMode)3, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 86 → 87 taken 10 times.
✗ Branch 86 → 96 not taken.
✓ Branch 88 → 75 taken 10 times.
✓ Branch 88 → 89 taken 2 times.
void masked_merge_impl_c_inner<(MaskMode)3, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 76 → 77 taken 10 times.
✗ Branch 76 → 86 not taken.
✓ Branch 78 → 67 taken 10 times.
✓ Branch 78 → 79 taken 2 times.
void masked_merge_impl_c_inner<(MaskMode)4, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 86 → 87 taken 50 times.
✗ Branch 86 → 96 not taken.
✓ Branch 88 → 75 taken 50 times.
✓ Branch 88 → 89 taken 10 times.
void masked_merge_impl_c_inner<(MaskMode)4, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 76 → 77 taken 30 times.
✗ Branch 76 → 86 not taken.
✓ Branch 78 → 67 taken 30 times.
✓ Branch 78 → 79 taken 6 times.
void masked_merge_impl_c_inner<(MaskMode)5, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 86 → 87 taken 10 times.
✗ Branch 86 → 96 not taken.
✓ Branch 88 → 75 taken 10 times.
✓ Branch 88 → 89 taken 2 times.
void masked_merge_impl_c_inner<(MaskMode)5, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 76 → 77 taken 10 times.
✗ Branch 76 → 86 not taken.
✓ Branch 78 → 67 taken 10 times.
✓ Branch 78 → 79 taken 2 times.
void masked_merge_impl_c_inner<(MaskMode)6, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 86 → 87 taken 10 times.
✗ Branch 86 → 96 not taken.
✓ Branch 88 → 75 taken 10 times.
✓ Branch 88 → 89 taken 2 times.
void masked_merge_impl_c_inner<(MaskMode)6, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 76 → 77 taken 10 times.
✗ Branch 76 → 86 not taken.
✓ Branch 78 → 67 taken 10 times.
✓ Branch 78 → 79 taken 2 times.
void masked_merge_impl_c_inner<(MaskMode)7, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 71 → 72 taken 30 times.
✗ Branch 71 → 81 not taken.
✓ Branch 73 → 63 taken 30 times.
✓ Branch 73 → 74 taken 6 times.
void masked_merge_impl_c_inner<(MaskMode)7, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 39 → 40 taken 30 times.
✗ Branch 39 → 46 not taken.
✓ Branch 41 → 37 taken 30 times.
✓ Branch 41 → 42 taken 6 times.
336 case 16: BLEND16_LOOP_C(16)
451 }
452 #undef BLEND16_LOOP_C
453 80 }
454
455 // Float version — opacity baked into rowprep, inner loop has no * opacity_f.
456 template<MaskMode maskMode, bool full_opacity>
457 AVS_FORCEINLINE static void masked_merge_impl_float_c_inner(
458 BYTE* p1, const BYTE* p2, const BYTE* mask,
459 int p1_pitch, int p2_pitch, int mask_pitch,
460 int width, int height, float opacity)
461 {
462 24 const float* maskp = reinterpret_cast<const float*>(mask);
463 24 const int mpx = mask_pitch / sizeof(float);
464 24 const int mask_adv = (maskMode == MASK420 || maskMode == MASK420_MPEG2 || maskMode == MASK420_TOPLEFT) ? mpx * 2 : mpx;
465
466 24 std::vector<float> eff_buf;
467
3/6
✓ Branch 4 → 5 taken 8 times.
✗ Branch 4 → 20 not taken.
✓ Branch 14 → 15 taken 4 times.
✗ Branch 14 → 27 not taken.
✓ Branch 25 → 26 taken 8 times.
✗ Branch 25 → 41 not taken.
20 if constexpr (maskMode != MASK444 || !full_opacity) eff_buf.resize(width);
468
469
8/8
✓ Branch 9 → 5 taken 20 times.
✓ Branch 9 → 10 taken 4 times.
✓ Branch 17 → 6 taken 40 times.
✓ Branch 17 → 18 taken 8 times.
✓ Branch 24 → 16 taken 20 times.
✓ Branch 24 → 25 taken 4 times.
✓ Branch 38 → 27 taken 40 times.
✓ Branch 38 → 39 taken 8 times.
144 for (int y = 0; y < height; y++) {
470 120 const float* eff = prepare_effective_mask_for_row_float_c<maskMode, full_opacity>(
471 maskp, mpx, width, eff_buf, opacity);
472 120 blend_masked_float_c_row(
473 reinterpret_cast<float*>(p1), reinterpret_cast<const float*>(p2), eff, width);
474 120 p1 += p1_pitch; p2 += p2_pitch; maskp += mask_adv;
475 }
476 24 }
477
478 // ---------------------------------------------------------------------------
479 // Outer: dispatch on full_opacity (opacity == max_pixel_value) at the call site.
480 // ---------------------------------------------------------------------------
481 template<MaskMode maskMode>
482 138 AVS_FORCEINLINE static void masked_merge_c_impl(
483 BYTE* p1, const BYTE* p2, const BYTE* mask,
484 int p1_pitch, int p2_pitch, int mask_pitch,
485 int width, int height, int opacity, int bits_per_pixel)
486 {
487 138 const int max_pixel_value = (1 << bits_per_pixel) - 1;
488
14/18
None:
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 5 not taken.
void masked_merge_c_impl<(MaskMode)0>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
void masked_merge_c_impl<(MaskMode)1>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 2 → 3 taken 12 times.
✓ Branch 2 → 4 taken 16 times.
void masked_merge_c_impl<(MaskMode)2>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 2 → 3 taken 4 times.
✓ Branch 2 → 4 taken 6 times.
void masked_merge_c_impl<(MaskMode)3>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 2 → 3 taken 4 times.
✓ Branch 2 → 4 taken 4 times.
void masked_merge_c_impl<(MaskMode)4>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 2 → 3 taken 12 times.
✓ Branch 2 → 4 taken 16 times.
void masked_merge_c_impl<(MaskMode)5>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 2 → 3 taken 4 times.
✓ Branch 2 → 4 taken 4 times.
void masked_merge_c_impl<(MaskMode)6>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 2 → 3 taken 4 times.
✓ Branch 2 → 4 taken 4 times.
void masked_merge_c_impl<(MaskMode)7>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 2 → 3 taken 24 times.
✓ Branch 2 → 4 taken 24 times.
138 if (opacity == max_pixel_value)
489 64 masked_merge_impl_c_inner<maskMode, true>(
490 p1, p2, mask, p1_pitch, p2_pitch, mask_pitch, width, height, opacity, bits_per_pixel);
491 else
492 74 masked_merge_impl_c_inner<maskMode, false>(
493 p1, p2, mask, p1_pitch, p2_pitch, mask_pitch, width, height, opacity, bits_per_pixel);
494 138 }
495
496 template<MaskMode maskMode>
497 24 AVS_FORCEINLINE static void masked_merge_float_c_impl(
498 BYTE* p1, const BYTE* p2, const BYTE* mask,
499 int p1_pitch, int p2_pitch, int mask_pitch,
500 int width, int height, float opacity_f)
501 {
502
6/16
void masked_merge_float_c_impl<(MaskMode)0>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 24 not taken.
void masked_merge_float_c_impl<(MaskMode)1>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✓ Branch 2 → 3 taken 4 times.
✓ Branch 2 → 24 taken 4 times.
void masked_merge_float_c_impl<(MaskMode)2>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 24 not taken.
void masked_merge_float_c_impl<(MaskMode)3>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 24 not taken.
void masked_merge_float_c_impl<(MaskMode)4>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✓ Branch 2 → 3 taken 4 times.
✓ Branch 2 → 24 taken 4 times.
void masked_merge_float_c_impl<(MaskMode)5>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 24 not taken.
void masked_merge_float_c_impl<(MaskMode)6>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 24 not taken.
void masked_merge_float_c_impl<(MaskMode)7>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, float):
✓ Branch 2 → 3 taken 4 times.
✓ Branch 2 → 13 taken 4 times.
24 if (opacity_f == 1.0f)
503 masked_merge_impl_float_c_inner<maskMode, true>(
504 p1, p2, mask, p1_pitch, p2_pitch, mask_pitch, width, height, opacity_f);
505 else
506 masked_merge_impl_float_c_inner<maskMode, false>(
507 p1, p2, mask, p1_pitch, p2_pitch, mask_pitch, width, height, opacity_f);
508 24 }
509
510 /*
511 * Family 1: weighted_merge — no mask, flat weight, >> 15 shift
512 * weight + invweight == 32768
513 */
514 using weighted_merge_fn_t = void(
515 BYTE* p1, const BYTE* p2,
516 int p1_pitch, int p2_pitch,
517 int width, int height,
518 int weight, int invweight,
519 int bits_per_pixel);
520
521 using weighted_merge_float_fn_t = void(
522 BYTE* p1, const BYTE* p2,
523 int p1_pitch, int p2_pitch,
524 int width, int height,
525 float weight_f);
526
527 /*
528 * Family 2: masked_merge — mask * opacity via magic_div
529 * opacity is pre-scaled: round(opacity_f * max_pixel_value)
530 */
531 using masked_merge_fn_t = void(
532 BYTE* p1, const BYTE* p2, const BYTE* mask,
533 int p1_pitch, int p2_pitch, int mask_pitch,
534 int width, int height,
535 int opacity,
536 int bits_per_pixel);
537
538 using masked_merge_float_fn_t = void(
539 BYTE* p1, const BYTE* p2, const BYTE* mask,
540 int p1_pitch, int p2_pitch, int mask_pitch,
541 int width, int height,
542 float opacity_f);
543
544 // Family 1 — C reference
545
546 void weighted_merge_return_a_or_b(BYTE* p1, const BYTE* p2,
547 int p1_pitch, int p2_pitch,
548 int width, int height,
549 int weight, int invweight,
550 int bits_per_pixel);
551
552 void weighted_merge_c(BYTE* p1, const BYTE* p2,
553 int p1_pitch, int p2_pitch,
554 int width, int height,
555 int weight, int invweight,
556 int bits_per_pixel);
557
558 void weighted_merge_float_c(BYTE* p1, const BYTE* p2,
559 int p1_pitch, int p2_pitch,
560 int width, int height,
561 float weight_f);
562
563 // Overlay blend C getters — dispatch on is_chroma × maskMode
564 masked_merge_fn_t* get_overlay_blend_masked_fn_c(bool is_chroma, MaskMode maskMode);
565 masked_merge_float_fn_t* get_overlay_blend_masked_float_fn_c(bool is_chroma, MaskMode maskMode);
566
567 using overlay_blend_plane_masked_opacity_t = void(BYTE* p1, const BYTE* p2, const BYTE* mask,
568 const int p1_pitch, const int p2_pitch, const int mask_pitch,
569 const int width, const int height, const float opacity_f,
570 const int bits_per_pixel);
571
572 /********************************
573 ********* Blend Opaque *********
574 ** Use for Lighten and Darken **
575 ********************************/
576 template<typename pixel_t>
577 AVS_FORCEINLINE pixel_t overlay_blend_opaque_c_core(const pixel_t p1, const pixel_t p2, const pixel_t mask) {
578
12/18
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 6 not taken.
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 11 not taken.
✗ Branch 14 → 15 not taken.
✗ Branch 14 → 16 not taken.
✓ Branch 38 → 39 taken 132 times.
✓ Branch 38 → 40 taken 86 times.
✓ Branch 43 → 44 taken 132 times.
✓ Branch 43 → 45 taken 86 times.
✓ Branch 48 → 49 taken 132 times.
✓ Branch 48 → 50 taken 86 times.
✓ Branch 56 → 57 taken 100 times.
✓ Branch 56 → 58 taken 86 times.
✓ Branch 61 → 62 taken 100 times.
✓ Branch 61 → 63 taken 86 times.
✓ Branch 66 → 67 taken 100 times.
✓ Branch 66 → 68 taken 86 times.
404 return (mask) ? p2 : p1;
579 }
580
581 // Mode: Darken/lighten
582
583 template<typename pixel_t>
584 void overlay_darken_c(BYTE *p1Y, BYTE *p1U, BYTE *p1V, const BYTE *p2Y, const BYTE *p2U, const BYTE *p2V, int p1_pitch, int p2_pitch, int width, int height);
585 template<typename pixel_t>
586 void overlay_lighten_c(BYTE *p1Y, BYTE *p1U, BYTE *p1V, const BYTE *p2Y, const BYTE *p2U, const BYTE *p2V, int p1_pitch, int p2_pitch, int width, int height);
587
588 // ---------------------------------------------------------------------------
589 // Packed RGBA (RGB32 / RGB64) blend — magic-div arithmetic.
590 //
591 // Per-pixel blend weight source:
592 // maskp8 == nullptr → alpha is ovrp[x*4+3] (Add: overlay's own alpha)
593 // maskp8 != nullptr → alpha is maskp[x] (Subtract: original alpha extracted
594 // before pre-inverting overlay in Layer::Create)
595 //
596 // alpha_eff = (alpha_src * opacity_i + half) / max_val
597 // result_ch = (dst_ch * (max - alpha_eff) + ovr_ch * alpha_eff + half) / max_val
598 //
599 // For Subtract, the overlay is pre-inverted in Layer::Create, so ovr_ch is already
600 // (max_val - original_ch) — no subtract logic is needed inside the kernel.
601 //
602 // opacity_i is in [0..max_pixel_value], the same convention as masked_merge.
603 // This is the interleaved analogue of masked_merge_impl for MASK444 planar
604 // data, using the correct ÷max_val formula so that all mask values [0..max]
605 // map linearly to the blend range without endpoint asymmetry.
606 // ---------------------------------------------------------------------------
607 template<typename pixel_t, bool has_separate_mask>
608 1 static void masked_blend_packedrgba_c(
609 BYTE* dstp8, const BYTE* ovrp8, const BYTE* maskp8,
610 int dst_pitch, int ovr_pitch, int mask_pitch,
611 int width, int height, int opacity_i)
612 {
613 1 pixel_t* dstp = reinterpret_cast<pixel_t*>(dstp8);
614 1 const pixel_t* ovrp = reinterpret_cast<const pixel_t*>(ovrp8);
615 1 const pixel_t* maskp = has_separate_mask ? reinterpret_cast<const pixel_t*>(maskp8) : nullptr;
616 1 dst_pitch /= sizeof(pixel_t);
617 1 ovr_pitch /= sizeof(pixel_t);
618 if constexpr (has_separate_mask)
619 mask_pitch /= sizeof(pixel_t);
620
621 // For packed RGB32/64, only 8 and 16 bpc exist; bpp derives from pixel_t.
622 1 constexpr uint32_t max_val = sizeof(pixel_t) == 1 ? 255u : 65535u;
623 1 constexpr uint32_t half = max_val / 2u;
624 1 constexpr int bpp = sizeof(pixel_t) == 1 ? 8 : 16;
625 1 const MagicDiv magic = get_magic_div(bpp);
626
627 // uint32_t arithmetic is safe: the maximum sum a*inv + b*alpha is bounded
628 // by max_val^2 = 65535^2 = 4,294,836,225 < UINT32_MAX; adding half keeps
629 // it within range. The 8-bit case is well within 32-bit even before that.
630
631
2/8
void masked_blend_packedrgba_c<unsigned char, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int):
✗ Branch 14 → 3 not taken.
✗ Branch 14 → 15 not taken.
void masked_blend_packedrgba_c<unsigned char, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int):
✗ Branch 14 → 3 not taken.
✗ Branch 14 → 15 not taken.
void masked_blend_packedrgba_c<unsigned short, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int):
✓ Branch 14 → 3 taken 2 times.
✓ Branch 14 → 15 taken 1 time.
void masked_blend_packedrgba_c<unsigned short, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int):
✗ Branch 14 → 3 not taken.
✗ Branch 14 → 15 not taken.
3 for (int y = 0; y < height; ++y) {
632
2/8
void masked_blend_packedrgba_c<unsigned char, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int):
✗ Branch 12 → 4 not taken.
✗ Branch 12 → 13 not taken.
void masked_blend_packedrgba_c<unsigned char, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int):
✗ Branch 12 → 4 not taken.
✗ Branch 12 → 13 not taken.
void masked_blend_packedrgba_c<unsigned short, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int):
✓ Branch 12 → 4 taken 10 times.
✓ Branch 12 → 13 taken 2 times.
void masked_blend_packedrgba_c<unsigned short, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int):
✗ Branch 12 → 4 not taken.
✗ Branch 12 → 13 not taken.
12 for (int x = 0; x < width; ++x) {
633 10 const uint32_t alpha_src = has_separate_mask ? (uint32_t)maskp[x] : (uint32_t)ovrp[x * 4 + 3];
634 20 const uint32_t alpha_eff = (uint32_t)magic_div_rt<pixel_t>(
635 10 alpha_src * (uint32_t)opacity_i + half, magic);
636 10 const uint32_t inv_alpha = max_val - alpha_eff;
637
638
2/8
void masked_blend_packedrgba_c<unsigned char, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int):
✗ Branch 10 → 7 not taken.
✗ Branch 10 → 11 not taken.
void masked_blend_packedrgba_c<unsigned char, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int):
✗ Branch 10 → 7 not taken.
✗ Branch 10 → 11 not taken.
void masked_blend_packedrgba_c<unsigned short, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int):
✓ Branch 10 → 7 taken 40 times.
✓ Branch 10 → 11 taken 10 times.
void masked_blend_packedrgba_c<unsigned short, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int):
✗ Branch 10 → 7 not taken.
✗ Branch 10 → 11 not taken.
50 for (int ch = 0; ch < 4; ++ch) {
639 40 dstp[x * 4 + ch] = (pixel_t)magic_div_rt<pixel_t>(
640 40 (uint32_t)dstp[x * 4 + ch] * inv_alpha + (uint32_t)ovrp[x * 4 + ch] * alpha_eff + half, magic);
641 }
642 }
643 2 dstp += dst_pitch;
644 2 ovrp += ovr_pitch;
645 if constexpr (has_separate_mask) maskp += mask_pitch;
646 }
647 1 }
648
649 #endif // __blend_common_h
650