GCC Code Coverage Report


Directory: avs_core/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 2.6% 192 / 0 / 7481
Functions: 4.2% 11 / 0 / 263
Branches: 1.9% 45 / 0 / 2410

filters/layer.hpp
Line Branch Exec Source
1
2 // Basic utils in C++ language, to be included in both base and processor specific (e.g. avx2) source modules, where they can
3 // be optimized for the specific instruction set.
4 // yuv add, subtract, mul, lighten, darken
5 // Chroma placement helpers (calculate_effective_mask*, prepare_effective_mask_for_row*)
6 // are now in overlay/blend_common.h, pulled in via layer.h.
7
8 // ---------------------------------------------------------------------------
9 // Rowprep function selectors — defined by the including TU to inject SIMD variants.
10 // Default: C scalar functions from overlay/blend_common.h.
11 //
12 // LAYER_ROWPREP_FN — spatial mask averaging (+ opacity baking when
13 // full_opacity=false.
14 // Used for the full_opacity=true path: returns only spatial
15 // averages (or maskp directly for MASK444).
16 //
17 // Including TU (e.g. layer_avx2.cpp) defines them before this #include:
18 // #define LAYER_ROWPREP_FN prepare_effective_mask_for_row_avx2
19 // to allow the same C template to compile with arch-spcific different rowprep variants
20 // ---------------------------------------------------------------------------
21 #ifndef LAYER_ROWPREP_FN
22 # define LAYER_ROWPREP_FN prepare_effective_mask_for_row
23 #endif
24
25 DISABLE_WARNING_PUSH
26 DISABLE_WARNING_UNREFERENCED_LOCAL_VARIABLE
27
28 // YUV(A) mul 8-16 bits
29 // full_opacity == true : rowprep returns mask-average; subsample-aware avg mask is put into effective_mask_buffer[x]. 444 case: returns maskp directly.
30 // full_opacity == false: rowprep pre-calculates with 'opacity' in the formulae, effective_mask_buffer is filled even for 444.
31 template<MaskMode maskMode, typename pixel_t, bool is_chroma, bool has_alpha, bool full_opacity>
32 3 static void layer_yuv_mul_c_inner(BYTE* dstp8, const BYTE* ovrp8, const BYTE* maskp8, int dst_pitch, int overlay_pitch, int mask_pitch, int width, int height, int opacity_i, int bits_per_pixel) {
33 3 pixel_t* dstp = reinterpret_cast<pixel_t*>(dstp8);
34 3 const pixel_t* ovrp = reinterpret_cast<const pixel_t*>(ovrp8);
35 3 const pixel_t* maskp = has_alpha ? reinterpret_cast<const pixel_t*>(maskp8) : nullptr;
36 3 dst_pitch /= sizeof(pixel_t);
37 3 overlay_pitch /= sizeof(pixel_t);
38 if constexpr (has_alpha)
39 mask_pitch /= sizeof(pixel_t);
40
41 if constexpr (sizeof(pixel_t) == 1)
42 3 bits_per_pixel = 8; // make quasi constexpr
43
44 3 const MagicDiv magic = get_magic_div(bits_per_pixel);
45 3 const int max_pixel_value = (1 << bits_per_pixel) - 1;
46 3 const int half = max_pixel_value / 2;
47
48 // Buffer: needed for subsampled spatial averaging, or MASK444+!full_opacity baking.
49 3 std::vector<pixel_t> effective_mask_buffer;
50 if constexpr (has_alpha && (maskMode != MASK444 || !full_opacity)) {
51 effective_mask_buffer.resize(width);
52 }
53
54
4/130
void layer_yuv_mul_c_inner<(MaskMode)0, unsigned char, true, false, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 5 not taken.
✗ Branch 11 → 12 not taken.
void layer_yuv_mul_c_inner<(MaskMode)1, unsigned char, true, false, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 5 not taken.
✗ Branch 11 → 12 not taken.
void layer_yuv_mul_c_inner<(MaskMode)1, unsigned char, true, false, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 5 not taken.
✗ Branch 11 → 12 not taken.
void layer_yuv_mul_c_inner<(MaskMode)1, unsigned char, true, true, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 13 → 6 not taken.
✗ Branch 13 → 14 not taken.
✗ Branch 21 → 6 not taken.
✗ Branch 21 → 22 not taken.
void layer_yuv_mul_c_inner<(MaskMode)1, unsigned short, true, false, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 5 not taken.
✗ Branch 11 → 12 not taken.
void layer_yuv_mul_c_inner<(MaskMode)1, unsigned short, true, false, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 5 not taken.
✗ Branch 11 → 12 not taken.
void layer_yuv_mul_c_inner<(MaskMode)1, unsigned short, true, true, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 13 → 6 not taken.
✗ Branch 13 → 14 not taken.
✗ Branch 21 → 6 not taken.
✗ Branch 21 → 22 not taken.
void layer_yuv_mul_c_inner<(MaskMode)2, unsigned char, true, false, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 5 not taken.
✗ Branch 11 → 12 not taken.
void layer_yuv_mul_c_inner<(MaskMode)2, unsigned char, true, false, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 5 not taken.
✗ Branch 11 → 12 not taken.
void layer_yuv_mul_c_inner<(MaskMode)2, unsigned char, true, true, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 13 → 6 not taken.
✗ Branch 13 → 14 not taken.
✗ Branch 21 → 6 not taken.
✗ Branch 21 → 22 not taken.
void layer_yuv_mul_c_inner<(MaskMode)2, unsigned short, true, false, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 5 not taken.
✗ Branch 11 → 12 not taken.
void layer_yuv_mul_c_inner<(MaskMode)2, unsigned short, true, false, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 5 not taken.
✗ Branch 11 → 12 not taken.
void layer_yuv_mul_c_inner<(MaskMode)2, unsigned short, true, true, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 13 → 6 not taken.
✗ Branch 13 → 14 not taken.
✗ Branch 21 → 6 not taken.
✗ Branch 21 → 22 not taken.
void layer_yuv_mul_c_inner<(MaskMode)3, unsigned char, true, false, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 5 not taken.
✗ Branch 11 → 12 not taken.
void layer_yuv_mul_c_inner<(MaskMode)3, unsigned char, true, false, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 5 not taken.
✗ Branch 11 → 12 not taken.
void layer_yuv_mul_c_inner<(MaskMode)3, unsigned char, true, true, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 13 → 6 not taken.
✗ Branch 13 → 14 not taken.
✗ Branch 21 → 6 not taken.
✗ Branch 21 → 22 not taken.
void layer_yuv_mul_c_inner<(MaskMode)3, unsigned short, true, false, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 5 not taken.
✗ Branch 11 → 12 not taken.
void layer_yuv_mul_c_inner<(MaskMode)3, unsigned short, true, false, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 5 not taken.
✗ Branch 11 → 12 not taken.
void layer_yuv_mul_c_inner<(MaskMode)3, unsigned short, true, true, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 13 → 6 not taken.
✗ Branch 13 → 14 not taken.
✗ Branch 21 → 6 not taken.
✗ Branch 21 → 22 not taken.
void layer_yuv_mul_c_inner<(MaskMode)4, unsigned char, true, false, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 5 not taken.
✗ Branch 11 → 12 not taken.
void layer_yuv_mul_c_inner<(MaskMode)4, unsigned char, true, false, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 5 not taken.
✗ Branch 11 → 12 not taken.
void layer_yuv_mul_c_inner<(MaskMode)4, unsigned char, true, true, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 13 → 6 not taken.
✗ Branch 13 → 14 not taken.
✗ Branch 21 → 6 not taken.
✗ Branch 21 → 22 not taken.
void layer_yuv_mul_c_inner<(MaskMode)4, unsigned short, true, false, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 5 not taken.
✗ Branch 11 → 12 not taken.
void layer_yuv_mul_c_inner<(MaskMode)4, unsigned short, true, false, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 5 not taken.
✗ Branch 11 → 12 not taken.
void layer_yuv_mul_c_inner<(MaskMode)4, unsigned short, true, true, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 13 → 6 not taken.
✗ Branch 13 → 14 not taken.
✗ Branch 21 → 6 not taken.
✗ Branch 21 → 22 not taken.
void layer_yuv_mul_c_inner<(MaskMode)5, unsigned char, true, false, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 5 not taken.
✗ Branch 11 → 12 not taken.
void layer_yuv_mul_c_inner<(MaskMode)5, unsigned char, true, false, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 5 not taken.
✗ Branch 11 → 12 not taken.
void layer_yuv_mul_c_inner<(MaskMode)5, unsigned char, true, true, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 13 → 6 not taken.
✗ Branch 13 → 14 not taken.
✗ Branch 21 → 6 not taken.
✗ Branch 21 → 22 not taken.
void layer_yuv_mul_c_inner<(MaskMode)5, unsigned short, true, false, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 5 not taken.
✗ Branch 11 → 12 not taken.
void layer_yuv_mul_c_inner<(MaskMode)5, unsigned short, true, false, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 5 not taken.
✗ Branch 11 → 12 not taken.
void layer_yuv_mul_c_inner<(MaskMode)5, unsigned short, true, true, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 13 → 6 not taken.
✗ Branch 13 → 14 not taken.
✗ Branch 21 → 6 not taken.
✗ Branch 21 → 22 not taken.
void layer_yuv_mul_c_inner<(MaskMode)6, unsigned char, true, false, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 5 not taken.
✗ Branch 11 → 12 not taken.
void layer_yuv_mul_c_inner<(MaskMode)6, unsigned char, true, false, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 5 not taken.
✗ Branch 11 → 12 not taken.
void layer_yuv_mul_c_inner<(MaskMode)6, unsigned char, true, true, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 13 → 6 not taken.
✗ Branch 13 → 14 not taken.
✗ Branch 21 → 6 not taken.
✗ Branch 21 → 22 not taken.
void layer_yuv_mul_c_inner<(MaskMode)6, unsigned short, true, false, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 5 not taken.
✗ Branch 11 → 12 not taken.
void layer_yuv_mul_c_inner<(MaskMode)6, unsigned short, true, false, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 5 not taken.
✗ Branch 11 → 12 not taken.
void layer_yuv_mul_c_inner<(MaskMode)6, unsigned short, true, true, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 13 → 6 not taken.
✗ Branch 13 → 14 not taken.
✗ Branch 21 → 6 not taken.
✗ Branch 21 → 22 not taken.
void layer_yuv_mul_c_inner<(MaskMode)7, unsigned char, false, false, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 5 not taken.
✗ Branch 11 → 12 not taken.
void layer_yuv_mul_c_inner<(MaskMode)7, unsigned char, false, false, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 11 → 5 taken 3 times.
✓ Branch 11 → 12 taken 1 time.
void layer_yuv_mul_c_inner<(MaskMode)7, unsigned char, false, true, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 12 → 5 not taken.
✗ Branch 12 → 13 not taken.
✗ Branch 13 → 5 not taken.
✗ Branch 13 → 14 not taken.
void layer_yuv_mul_c_inner<(MaskMode)7, unsigned char, true, false, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 5 not taken.
✗ Branch 11 → 12 not taken.
void layer_yuv_mul_c_inner<(MaskMode)7, unsigned char, true, false, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 11 → 5 taken 6 times.
✓ Branch 11 → 12 taken 2 times.
void layer_yuv_mul_c_inner<(MaskMode)7, unsigned char, true, true, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 12 → 5 not taken.
✗ Branch 12 → 13 not taken.
✗ Branch 13 → 5 not taken.
✗ Branch 13 → 14 not taken.
void layer_yuv_mul_c_inner<(MaskMode)7, unsigned short, false, false, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 5 not taken.
✗ Branch 11 → 12 not taken.
void layer_yuv_mul_c_inner<(MaskMode)7, unsigned short, false, false, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 5 not taken.
✗ Branch 11 → 12 not taken.
void layer_yuv_mul_c_inner<(MaskMode)7, unsigned short, false, true, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 12 → 5 not taken.
✗ Branch 12 → 13 not taken.
✗ Branch 13 → 5 not taken.
✗ Branch 13 → 14 not taken.
void layer_yuv_mul_c_inner<(MaskMode)7, unsigned short, true, false, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 5 not taken.
✗ Branch 11 → 12 not taken.
void layer_yuv_mul_c_inner<(MaskMode)7, unsigned short, true, false, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 5 not taken.
✗ Branch 11 → 12 not taken.
void layer_yuv_mul_c_inner<(MaskMode)7, unsigned short, true, true, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 12 → 5 not taken.
✗ Branch 12 → 13 not taken.
✗ Branch 13 → 5 not taken.
✗ Branch 13 → 14 not taken.
12 for (int y = 0; y < height; ++y) {
55 9 const pixel_t* effective_mask_ptr = nullptr;
56
57 // Rowprep: full_opacity path returns spatial avg (or maskp for MASK444).
58 // !full_opacity path bakes (avg * opacity_i) / div
59 if constexpr (has_alpha) {
60 if constexpr (full_opacity)
61 effective_mask_ptr = LAYER_ROWPREP_FN<maskMode, pixel_t, true>(maskp, mask_pitch, width, effective_mask_buffer);
62 else
63 effective_mask_ptr = LAYER_ROWPREP_FN<maskMode, pixel_t, false>(maskp, mask_pitch, width, effective_mask_buffer, opacity_i, half, magic);
64 }
65
66 // Main blending loop — alpha_mask is fully prepared by rowprep.
67
4/130
void layer_yuv_mul_c_inner<(MaskMode)0, unsigned char, true, false, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 9 → 6 not taken.
✗ Branch 9 → 10 not taken.
void layer_yuv_mul_c_inner<(MaskMode)1, unsigned char, true, false, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 9 → 6 not taken.
✗ Branch 9 → 10 not taken.
void layer_yuv_mul_c_inner<(MaskMode)1, unsigned char, true, false, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 9 → 6 not taken.
✗ Branch 9 → 10 not taken.
void layer_yuv_mul_c_inner<(MaskMode)1, unsigned char, true, true, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 8 not taken.
✗ Branch 11 → 12 not taken.
✗ Branch 19 → 16 not taken.
✗ Branch 19 → 20 not taken.
void layer_yuv_mul_c_inner<(MaskMode)1, unsigned short, true, false, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 9 → 6 not taken.
✗ Branch 9 → 10 not taken.
void layer_yuv_mul_c_inner<(MaskMode)1, unsigned short, true, false, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 9 → 6 not taken.
✗ Branch 9 → 10 not taken.
void layer_yuv_mul_c_inner<(MaskMode)1, unsigned short, true, true, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 8 not taken.
✗ Branch 11 → 12 not taken.
✗ Branch 19 → 16 not taken.
✗ Branch 19 → 20 not taken.
void layer_yuv_mul_c_inner<(MaskMode)2, unsigned char, true, false, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 9 → 6 not taken.
✗ Branch 9 → 10 not taken.
void layer_yuv_mul_c_inner<(MaskMode)2, unsigned char, true, false, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 9 → 6 not taken.
✗ Branch 9 → 10 not taken.
void layer_yuv_mul_c_inner<(MaskMode)2, unsigned char, true, true, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 8 not taken.
✗ Branch 11 → 12 not taken.
✗ Branch 19 → 16 not taken.
✗ Branch 19 → 20 not taken.
void layer_yuv_mul_c_inner<(MaskMode)2, unsigned short, true, false, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 9 → 6 not taken.
✗ Branch 9 → 10 not taken.
void layer_yuv_mul_c_inner<(MaskMode)2, unsigned short, true, false, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 9 → 6 not taken.
✗ Branch 9 → 10 not taken.
void layer_yuv_mul_c_inner<(MaskMode)2, unsigned short, true, true, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 8 not taken.
✗ Branch 11 → 12 not taken.
✗ Branch 19 → 16 not taken.
✗ Branch 19 → 20 not taken.
void layer_yuv_mul_c_inner<(MaskMode)3, unsigned char, true, false, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 9 → 6 not taken.
✗ Branch 9 → 10 not taken.
void layer_yuv_mul_c_inner<(MaskMode)3, unsigned char, true, false, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 9 → 6 not taken.
✗ Branch 9 → 10 not taken.
void layer_yuv_mul_c_inner<(MaskMode)3, unsigned char, true, true, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 8 not taken.
✗ Branch 11 → 12 not taken.
✗ Branch 19 → 16 not taken.
✗ Branch 19 → 20 not taken.
void layer_yuv_mul_c_inner<(MaskMode)3, unsigned short, true, false, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 9 → 6 not taken.
✗ Branch 9 → 10 not taken.
void layer_yuv_mul_c_inner<(MaskMode)3, unsigned short, true, false, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 9 → 6 not taken.
✗ Branch 9 → 10 not taken.
void layer_yuv_mul_c_inner<(MaskMode)3, unsigned short, true, true, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 8 not taken.
✗ Branch 11 → 12 not taken.
✗ Branch 19 → 16 not taken.
✗ Branch 19 → 20 not taken.
void layer_yuv_mul_c_inner<(MaskMode)4, unsigned char, true, false, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 9 → 6 not taken.
✗ Branch 9 → 10 not taken.
void layer_yuv_mul_c_inner<(MaskMode)4, unsigned char, true, false, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 9 → 6 not taken.
✗ Branch 9 → 10 not taken.
void layer_yuv_mul_c_inner<(MaskMode)4, unsigned char, true, true, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 8 not taken.
✗ Branch 11 → 12 not taken.
✗ Branch 19 → 16 not taken.
✗ Branch 19 → 20 not taken.
void layer_yuv_mul_c_inner<(MaskMode)4, unsigned short, true, false, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 9 → 6 not taken.
✗ Branch 9 → 10 not taken.
void layer_yuv_mul_c_inner<(MaskMode)4, unsigned short, true, false, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 9 → 6 not taken.
✗ Branch 9 → 10 not taken.
void layer_yuv_mul_c_inner<(MaskMode)4, unsigned short, true, true, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 8 not taken.
✗ Branch 11 → 12 not taken.
✗ Branch 19 → 16 not taken.
✗ Branch 19 → 20 not taken.
void layer_yuv_mul_c_inner<(MaskMode)5, unsigned char, true, false, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 9 → 6 not taken.
✗ Branch 9 → 10 not taken.
void layer_yuv_mul_c_inner<(MaskMode)5, unsigned char, true, false, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 9 → 6 not taken.
✗ Branch 9 → 10 not taken.
void layer_yuv_mul_c_inner<(MaskMode)5, unsigned char, true, true, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 8 not taken.
✗ Branch 11 → 12 not taken.
✗ Branch 19 → 16 not taken.
✗ Branch 19 → 20 not taken.
void layer_yuv_mul_c_inner<(MaskMode)5, unsigned short, true, false, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 9 → 6 not taken.
✗ Branch 9 → 10 not taken.
void layer_yuv_mul_c_inner<(MaskMode)5, unsigned short, true, false, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 9 → 6 not taken.
✗ Branch 9 → 10 not taken.
void layer_yuv_mul_c_inner<(MaskMode)5, unsigned short, true, true, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 8 not taken.
✗ Branch 11 → 12 not taken.
✗ Branch 19 → 16 not taken.
✗ Branch 19 → 20 not taken.
void layer_yuv_mul_c_inner<(MaskMode)6, unsigned char, true, false, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 9 → 6 not taken.
✗ Branch 9 → 10 not taken.
void layer_yuv_mul_c_inner<(MaskMode)6, unsigned char, true, false, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 9 → 6 not taken.
✗ Branch 9 → 10 not taken.
void layer_yuv_mul_c_inner<(MaskMode)6, unsigned char, true, true, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 8 not taken.
✗ Branch 11 → 12 not taken.
✗ Branch 19 → 16 not taken.
✗ Branch 19 → 20 not taken.
void layer_yuv_mul_c_inner<(MaskMode)6, unsigned short, true, false, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 9 → 6 not taken.
✗ Branch 9 → 10 not taken.
void layer_yuv_mul_c_inner<(MaskMode)6, unsigned short, true, false, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 9 → 6 not taken.
✗ Branch 9 → 10 not taken.
void layer_yuv_mul_c_inner<(MaskMode)6, unsigned short, true, true, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 11 → 8 not taken.
✗ Branch 11 → 12 not taken.
✗ Branch 19 → 16 not taken.
✗ Branch 19 → 20 not taken.
void layer_yuv_mul_c_inner<(MaskMode)7, unsigned char, false, false, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 9 → 6 not taken.
✗ Branch 9 → 10 not taken.
void layer_yuv_mul_c_inner<(MaskMode)7, unsigned char, false, false, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 9 → 6 taken 24 times.
✓ Branch 9 → 10 taken 3 times.
void layer_yuv_mul_c_inner<(MaskMode)7, unsigned char, false, true, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 10 → 7 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 11 → 8 not taken.
✗ Branch 11 → 12 not taken.
void layer_yuv_mul_c_inner<(MaskMode)7, unsigned char, true, false, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 9 → 6 not taken.
✗ Branch 9 → 10 not taken.
void layer_yuv_mul_c_inner<(MaskMode)7, unsigned char, true, false, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 9 → 6 taken 48 times.
✓ Branch 9 → 10 taken 6 times.
void layer_yuv_mul_c_inner<(MaskMode)7, unsigned char, true, true, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 10 → 7 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 11 → 8 not taken.
✗ Branch 11 → 12 not taken.
void layer_yuv_mul_c_inner<(MaskMode)7, unsigned short, false, false, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 9 → 6 not taken.
✗ Branch 9 → 10 not taken.
void layer_yuv_mul_c_inner<(MaskMode)7, unsigned short, false, false, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 9 → 6 not taken.
✗ Branch 9 → 10 not taken.
void layer_yuv_mul_c_inner<(MaskMode)7, unsigned short, false, true, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 10 → 7 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 11 → 8 not taken.
✗ Branch 11 → 12 not taken.
void layer_yuv_mul_c_inner<(MaskMode)7, unsigned short, true, false, false>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 9 → 6 not taken.
✗ Branch 9 → 10 not taken.
void layer_yuv_mul_c_inner<(MaskMode)7, unsigned short, true, false, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 9 → 6 not taken.
✗ Branch 9 → 10 not taken.
void layer_yuv_mul_c_inner<(MaskMode)7, unsigned short, true, true, true>(unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 10 → 7 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 11 → 8 not taken.
✗ Branch 11 → 12 not taken.
81 for (int x = 0; x < width; ++x) {
68 // has_alpha=true: rowprep baked level in (!full_opacity) or returned avg (full_opacity).
69 // has_alpha=false: flat level, no mask.
70 72 const uint32_t alpha_mask = has_alpha ? effective_mask_ptr[x] : opacity_i;
71 72 const uint32_t inv_alpha = max_pixel_value - alpha_mask;
72 uint32_t target_pixel;
73
74 if constexpr (!is_chroma) {
75 // luma: blend towards the "Multiplied" product, no rounding is done here.
76 // Calculate the multiplied product (A*B)/max
77 // SIMD hint:
78 // - on Intel for bits_per_pixel == 16, use _mm_mulhi_epu16 to get the high 16 bits of the 16x16->32 product.
79 // For lower bit depths, use _mm_mullo_epi16 and shift as needed.
80 // This means a separate code path for 10-14 and exact 16-bit pixels.
81 // - For universal 10-16 bit support on Intel, widen uint16_t to uint32_t, then
82 // use _mm_mullo_epi32 for full 32-bit multiplication, then shift right by bits_per_pixel and pack back to uint16_t.
83 // uint32_t case is needed to hint that the product result is also unsigned.
84 24 const pixel_t prod = (pixel_t)(((uint32_t)ovrp[x] * (uint32_t)dstp[x]) >> bits_per_pixel);
85 24 target_pixel = prod;
86 // was: dstp[x] = (pixel_t)(dstp[x] + ((((((calc_t)ovrp[x] * dstp[x]) >> bits_per_pixel) - dstp[x]) * alpha_mask) >> bits_per_pixel));
87 }
88 else {
89 // Note: when use_chrome=false, ovrp is prefilled with neutral, so the same formula applies for both modes
90 // CHROMA (Normal): Blend towards the overlay chroma (use_chroma=true) or towards neutral (use_chroma=false).
91 // Instead of dst + ((ovr - dst) * alpha) >> bits we use ((dst * (max - alpha)) + (ovr * alpha)) / max
92 // U = U + ( ((Uovr - U)*level) >> 8 )
93 // V = V + ( ((Vovr - V)*level) >> 8 )
94 48 target_pixel = (uint32_t)ovrp[x];
95 // for use_chroma = false, ovrp is prefilled with neutral
96 // was: dstp[x] = (pixel_t)(dstp[x] + (((calc_t)(ovrp[x] - dstp[x]) * alpha_mask) >> bits_per_pixel));
97 // The YUY2 MMX heritage (cargo cult programming) of halving the strength is finally eliminated
98 /*
99 const int half = 1 << (bits_per_pixel - 1);
100 dstp[x] = (pixel_t)(dstp[x] + (((calc_t)(half - dstp[x]) * (alpha_mask / 2)) >> bits_per_pixel));
101 // U = U + ( ((128 - U)*(level/2)) >> 8 )
102 // V = V + ( ((128 - V)*(level/2)) >> 8 )
103 */
104 }
105
106 144 dstp[x] = (pixel_t)magic_div_rt<pixel_t>((uint32_t)dstp[x] * inv_alpha + target_pixel * alpha_mask + half, magic);
107 }
108 9 dstp += dst_pitch;
109 9 ovrp += overlay_pitch;
110 if constexpr (has_alpha) {
111 if constexpr (maskMode == MASK420 || maskMode == MASK420_MPEG2 || maskMode == MASK420_TOPLEFT)
112 maskp += mask_pitch * 2;
113 else
114 maskp += mask_pitch;
115 }
116 }
117 3 }
118
119 // Outer dispatcher: full_opacity branch.
120 template<MaskMode maskMode, typename pixel_t, bool is_chroma, bool has_alpha>
121 3 static void layer_yuv_mul_c(BYTE* dstp8, const BYTE* ovrp8, const BYTE* maskp8, int dst_pitch, int overlay_pitch, int mask_pitch, int width, int height, int opacity_i, int bits_per_pixel) {
122 if constexpr (!has_alpha) {
123 // No mask; full_opacity choice is irrelevant; use true to skip dead buffer allocation.
124 3 layer_yuv_mul_c_inner<maskMode, pixel_t, is_chroma, false, true>(
125 dstp8, ovrp8, maskp8, dst_pitch, overlay_pitch, mask_pitch, width, height, opacity_i, bits_per_pixel);
126 } else {
127 const int max_pixel_value = (1 << bits_per_pixel) - 1;
128 if (opacity_i >= max_pixel_value) // full opacity
129 layer_yuv_mul_c_inner<maskMode, pixel_t, is_chroma, true, true>(
130 dstp8, ovrp8, maskp8, dst_pitch, overlay_pitch, mask_pitch, width, height, opacity_i, bits_per_pixel);
131 else
132 layer_yuv_mul_c_inner<maskMode, pixel_t, is_chroma, false, false>(
133 dstp8, ovrp8, maskp8, dst_pitch, overlay_pitch, mask_pitch, width, height, opacity_i, bits_per_pixel);
134 }
135 3 }
136
137 // YUV(A) mul 32 bits
138 template<MaskMode maskMode, bool is_chroma, bool has_alpha>
139 static void layer_yuv_mul_f_c(BYTE* dstp8, const BYTE* ovrp8, const BYTE* maskp8, int dst_pitch, int overlay_pitch, int mask_pitch, int width, int height, float opacity) {
140 float* dstp = reinterpret_cast<float*>(dstp8);
141 const float* ovrp = reinterpret_cast<const float*>(ovrp8);
142 const float* maskp = reinterpret_cast<const float*>(maskp8);
143 dst_pitch /= sizeof(float);
144 overlay_pitch /= sizeof(float);
145 mask_pitch /= sizeof(float);
146
147 // precalculate mask buffer
148 std::vector<float> effective_mask_buffer;
149 if constexpr (has_alpha && maskMode != MASK444) {
150 effective_mask_buffer.resize(width);
151 }
152
153 for (int y = 0; y < height; ++y) {
154 const float* effective_mask_ptr = nullptr;
155
156 // precalculate effective mask for this row
157 if constexpr (has_alpha) {
158 effective_mask_ptr = prepare_effective_mask_for_row_float_c<maskMode>(maskp, mask_pitch, width, effective_mask_buffer);
159 }
160
161 // blending loop
162 for (int x = 0; x < width; ++x) {
163 float effective_mask = has_alpha ? effective_mask_ptr[x] : 0.0f;
164 float alpha_mask = has_alpha ? effective_mask * opacity : opacity;
165
166 if constexpr (!is_chroma)
167 dstp[x] = dstp[x] + (ovrp[x] * dstp[x] - dstp[x]) * alpha_mask;
168 else {
169 // Note: when use_chrome=false, ovrp is prefilled with neutral, so the same formula applies for both modes
170 dstp[x] = dstp[x] + (ovrp[x] - dstp[x]) * alpha_mask;
171 }
172 }
173 dstp += dst_pitch;
174 ovrp += overlay_pitch;
175 if constexpr (has_alpha) {
176 if constexpr (maskMode == MASK420 || maskMode == MASK420_MPEG2 || maskMode == MASK420_TOPLEFT)
177 maskp += mask_pitch * 2;
178 else
179 maskp += mask_pitch;
180 }
181 }
182 }
183
184 /* Comparison of Multiply (Mul) blend mode: Overlay vs. Layer
185 * Luma (Y): Compatible. Both use standard (Base * Overlay) / Max logic.
186 * Chroma (UV): Incompatible. They utilize different "intent" for color:
187 * - Overlay (Legacy): Dynamic desaturation. Base chroma is pulled toward
188 * neutral (128/0.0) scaled by the specific Overlay Luma intensity (O_Y).
189 * Formula: Result_UV = (Base_UV * O_Y + Neutral * (Max - O_Y)) / Max
190 * - Layer (use_chroma=false): Static desaturation. Ignores overlay pixels
191 * entirely; blends toward a fixed neutral point via global opacity/mask.
192 * Formula: Result_UV = Base_UV + (Neutral - Base_UV) * Mask_Opacity
193 * Summary: Overlay treats darkness as a "color vacuum" (luma-dependent),
194 * while Layer treats Y and UV as independent channels.
195 * The function would need all plane parameters and work like lighten/darken instead of
196 * template<MaskMode maskMode, bool is_chroma, bool has_alpha>
197 * static void layer_yuv_mul_f_c(BYTE* dstp8, const BYTE* ovrp8, const BYTE* maskp8, int dst_pitch, int overlay_pitch, int mask_pitch, int width, int height, float opacity) {
198 * like this (?):
199 * template<int mode, MaskMode maskMode, typename pixel_t, bool lumaonly, bool has_alpha>
200 * static void layer_yuv_mul_overlaystyle_f_c(
201 */
202
203 // Unlike RGBA version, YUVA does not update destination alpha
204 // so no "blend_alpha" template parameter like at planar rgb lighten_darken
205
206 // Note, that we always call one instance of the filter: the lumaonly==false version,
207 // since the filter handles U and V first, then recursively calls itself with lumaonly==true;
208 // the chroma part needs unaltered luma for decision, so we delay Y processing.
209 // Except Y-only greayscale input, where only luma plane exists.
210 template<int mode, MaskMode maskMode, typename pixel_t, bool lumaonly, bool has_alpha>
211 static void layer_yuv_lighten_darken_c(
212 BYTE* dstp8, BYTE* dstp8_u, BYTE* dstp8_v,/* BYTE* dstp8_a,*/
213 const BYTE* ovrp8, const BYTE* ovrp8_u, const BYTE* ovrp8_v, const BYTE* maskp8,
214 int dst_pitch, int dst_pitchUV,
215 int overlay_pitch, int overlay_pitchUV,
216 int mask_pitch,
217 int width, int height, int opacity_i, int thresh,
218 int bits_per_pixel) {
219
220 pixel_t* dstp = reinterpret_cast<pixel_t*>(dstp8);
221 pixel_t* dstp_u = reinterpret_cast<pixel_t*>(dstp8_u);
222 pixel_t* dstp_v = reinterpret_cast<pixel_t*>(dstp8_v);
223 // pixel_t* dstp_a = reinterpret_cast<pixel_t *>(dstp8_a); // not destination alpha update
224
225 const pixel_t* ovrp = reinterpret_cast<const pixel_t*>(ovrp8);
226 const pixel_t* ovrp_u = reinterpret_cast<const pixel_t*>(ovrp8_u);
227 const pixel_t* ovrp_v = reinterpret_cast<const pixel_t*>(ovrp8_v);
228 const pixel_t* maskp = has_alpha ? reinterpret_cast<const pixel_t*>(maskp8) : nullptr;
229
230 dst_pitch /= sizeof(pixel_t);
231 dst_pitchUV /= sizeof(pixel_t);
232 overlay_pitch /= sizeof(pixel_t);
233 overlay_pitchUV /= sizeof(pixel_t);
234 if constexpr (has_alpha)
235 mask_pitch /= sizeof(pixel_t);
236
237 const int cwidth = (maskMode == MASK444) ? width : (maskMode == MASK411) ? width >> 2 : width >> 1; // 444:/1 420,422:/2 411:/4
238 const int cheight = (maskMode == MASK444 || maskMode == MASK422 || maskMode == MASK422_MPEG2 || maskMode == MASK422_TOPLEFT || maskMode == MASK411) ? height : height >> 1; // 444,422,411:/1 420:/2
239
240 // In lighten/darken we need 3 buffers:
241 std::vector<pixel_t> ovr_buffer;
242 std::vector<pixel_t> src_buffer;
243 std::vector<pixel_t> mask_buffer;
244
245 // precalculate mask buffer et al.
246 if constexpr (maskMode != MASK444) {
247 ovr_buffer.resize(cwidth);
248 src_buffer.resize(cwidth);
249 if constexpr (has_alpha)
250 mask_buffer.resize(cwidth);
251 }
252
253 if constexpr (sizeof(pixel_t) == 1)
254 bits_per_pixel = 8; // make quasi constexpr
255
256 const MagicDiv magic = get_magic_div(bits_per_pixel);
257 const int max_pixel_value = (1 << bits_per_pixel) - 1;
258 const int half = max_pixel_value / 2;
259
260 // for subsampled color spaces first do chroma, luma is only used for decision
261 // second pass will do luma only
262 for (int y = 0; y < cheight; ++y) {
263
264 // Prepare all three pointers using the helper, full-opacity mode, no opacity_i-magicdiv baking
265 const pixel_t* ovr_ptr = prepare_effective_mask_for_row<maskMode, pixel_t>(ovrp, overlay_pitch, cwidth, ovr_buffer);
266 const pixel_t* src_ptr = prepare_effective_mask_for_row<maskMode, pixel_t>(dstp, dst_pitch, cwidth, src_buffer);
267 const pixel_t* effective_mask_ptr = nullptr;
268 if constexpr (has_alpha) {
269 effective_mask_ptr = prepare_effective_mask_for_row<maskMode, pixel_t>(maskp, mask_pitch, cwidth, mask_buffer);
270 }
271
272 for (int x = 0; x < cwidth; ++x) {
273 // opacity_i is in [0..max_pixel_value], the same convention as masked_merge.
274 uint32_t alpha_eff;
275 if constexpr (has_alpha) {
276 const uint32_t alpha_src = (uint32_t)effective_mask_ptr[x];
277 alpha_eff = (uint32_t)magic_div_rt<pixel_t>(alpha_src * (uint32_t)opacity_i + half, magic);
278 }
279 else {
280 alpha_eff = opacity_i;
281 }
282
283 int ovr = ovr_ptr[x];
284 int src = src_ptr[x];
285
286 // If the threshold isn't met, the overlay weight becomes 0 (no change to dst)
287 if constexpr (mode == LIGHTEN) {
288 if (!(ovr > (src + thresh))) alpha_eff = 0;
289 }
290 else { // DARKEN
291 if (!(ovr < (src - thresh))) alpha_eff = 0;
292 }
293
294 const uint32_t inv_alpha = max_pixel_value - alpha_eff;
295
296 // formula: dst = (dst * inv_alpha + ovr * alpha_eff) / max_val
297 if constexpr (!lumaonly)
298 {
299 // chroma u,v
300 dstp_u[x] = (pixel_t)magic_div_rt<pixel_t>((uint32_t)dstp_u[x] * inv_alpha + (uint32_t)ovrp_u[x] * alpha_eff + half, magic);
301 dstp_v[x] = (pixel_t)magic_div_rt<pixel_t>((uint32_t)dstp_v[x] * inv_alpha + (uint32_t)ovrp_v[x] * alpha_eff + half, magic);
302 }
303
304 // for 444: update here, width/height is the same as for chroma
305 if constexpr (maskMode == MASK444)
306 dstp[x] = (pixel_t)magic_div_rt<pixel_t>((uint32_t)dstp[x] * inv_alpha + (uint32_t)ovrp[x] * alpha_eff + half, magic);
307 }
308 if constexpr (maskMode == MASK420 || maskMode == MASK420_MPEG2 || maskMode == MASK420_TOPLEFT) {
309 dstp += dst_pitch * 2; // skip vertical subsampling
310 ovrp += overlay_pitch * 2;
311 if constexpr (has_alpha) {
312 //dstp_a += dst_pitch * 2;
313 maskp += mask_pitch * 2;
314 }
315 }
316 else {
317 dstp += dst_pitch;
318 ovrp += overlay_pitch;
319 if constexpr (has_alpha) {
320 //dstp_a += dst_pitch;
321 maskp += mask_pitch;
322 }
323 }
324
325 if constexpr (!lumaonly) {
326 dstp_u += dst_pitchUV;
327 dstp_v += dst_pitchUV;
328 ovrp_u += overlay_pitchUV;
329 ovrp_v += overlay_pitchUV;
330 }
331
332 }
333
334 dst_pitch *= sizeof(pixel_t);
335 dst_pitchUV *= sizeof(pixel_t);
336 overlay_pitch *= sizeof(pixel_t);
337 overlay_pitchUV *= sizeof(pixel_t);
338 mask_pitch *= sizeof(pixel_t);
339
340 // Phase #2 recursively call the same function, but with lumaonly=true to update luma plane using the original chroma planes for decision
341 // make luma
342 if constexpr (!lumaonly && maskMode != MASK444)
343 layer_yuv_lighten_darken_c<mode, MASK444, pixel_t, true /* lumaonly*/, has_alpha>(
344 dstp8, dstp8_u, dstp8_v, //dstp8_a,
345 ovrp8, ovrp8_u, ovrp8_v, maskp8,
346 dst_pitch, dst_pitchUV, overlay_pitch, overlay_pitchUV, mask_pitch,
347 width, height, opacity_i, thresh, bits_per_pixel);
348 }
349
350 template<int mode, MaskMode maskMode, bool lumaonly, bool has_alpha>
351 static void layer_yuv_lighten_darken_f_c(
352 BYTE* dstp8, BYTE* dstp8_u, BYTE* dstp8_v /*, BYTE* dstp8_a*/,
353 const BYTE* ovrp8, const BYTE* ovrp8_u, const BYTE* ovrp8_v, const BYTE* maskp8,
354 int dst_pitch, int dst_pitchUV,
355 int overlay_pitch, int overlay_pitchUV,
356 int mask_pitch,
357 int width, int height, float opacity, float thresh) {
358
359 float* dstp = reinterpret_cast<float*>(dstp8);
360 float* dstp_u = reinterpret_cast<float*>(dstp8_u);
361 float* dstp_v = reinterpret_cast<float*>(dstp8_v);
362 //float* dstp_a = reinterpret_cast<float *>(dstp8_a);
363
364 const float* ovrp = reinterpret_cast<const float*>(ovrp8);
365 const float* ovrp_u = reinterpret_cast<const float*>(ovrp8_u);
366 const float* ovrp_v = reinterpret_cast<const float*>(ovrp8_v);
367 const float* maskp = has_alpha ? reinterpret_cast<const float*>(maskp8) : nullptr;
368
369 dst_pitch /= sizeof(float);
370 dst_pitchUV /= sizeof(float);
371 overlay_pitch /= sizeof(float);
372 overlay_pitchUV /= sizeof(float);
373 if constexpr (has_alpha)
374 mask_pitch /= sizeof(float);
375
376 const int cwidth = (maskMode == MASK444) ? width : (maskMode == MASK411) ? width >> 2 : width >> 1; // 444:/1 420,422:/2 411:/4
377 const int cheight = (maskMode == MASK444 || maskMode == MASK422 || maskMode == MASK422_MPEG2 || maskMode == MASK422_TOPLEFT || maskMode == MASK411) ? height : height >> 1; // 444,422,411:/1 420:/2
378
379 // In lighten/darken we need 3 buffers:
380 std::vector<float> ovr_buffer;
381 std::vector<float> src_buffer;
382 std::vector<float> mask_buffer;
383
384 // precalculate mask buffer et al.
385 if constexpr (maskMode != MASK444) {
386 ovr_buffer.resize(cwidth);
387 src_buffer.resize(cwidth);
388 if constexpr (has_alpha)
389 mask_buffer.resize(cwidth);
390 }
391
392 // for subsampled color spaces first do chroma, because luma is used for decision
393 // second pass will do luma only
394 for (int y = 0; y < cheight; ++y) {
395 const float* ovr_ptr = prepare_effective_mask_for_row_float_c<maskMode>(ovrp, overlay_pitch, cwidth, ovr_buffer);
396 const float* src_ptr = prepare_effective_mask_for_row_float_c<maskMode>(dstp, dst_pitch, cwidth, src_buffer);
397 const float* effective_mask_ptr = nullptr;
398 if constexpr (has_alpha) {
399 effective_mask_ptr = prepare_effective_mask_for_row_float_c<maskMode>(maskp, mask_pitch, cwidth, mask_buffer);
400 }
401
402 for (int x = 0; x < cwidth; ++x) {
403 float alpha_eff = has_alpha ? effective_mask_ptr[x] * opacity : opacity;
404
405 float ovr = ovr_ptr[x];
406 float src = src_ptr[x];
407 if constexpr (mode == LIGHTEN) {
408 if (!(ovr > (src + thresh))) alpha_eff = 0;
409 }
410 else {// DARKEN
411 if (!(ovr < (src - thresh))) alpha_eff = 0;
412 }
413
414 if constexpr (!lumaonly)
415 {
416 // chroma u,v
417 dstp_u[x] = dstp_u[x] + (ovrp_u[x] - dstp_u[x]) * alpha_eff;
418 dstp_v[x] = dstp_v[x] + (ovrp_v[x] - dstp_v[x]) * alpha_eff;
419 //dstp_a[x] = dstp_a[x] + (maskp[x] - dstp_a[x]) * alpha_eff;
420 }
421
422 // for 444: update here, width/height is the same as for chroma
423 if constexpr (maskMode == MASK444)
424 dstp[x] = dstp[x] + (ovrp[x] - dstp[x]) * alpha_eff;
425 }
426 if constexpr (maskMode == MASK420 || maskMode == MASK420_MPEG2 || maskMode == MASK420_TOPLEFT) {
427 dstp += dst_pitch * 2; // skip vertical subsampling
428 ovrp += overlay_pitch * 2;
429 if constexpr (has_alpha) {
430 //dstp_a += dst_pitch * 2;
431 maskp += mask_pitch * 2;
432 }
433 }
434 else {
435 dstp += dst_pitch;
436 ovrp += overlay_pitch;
437 if constexpr (has_alpha) {
438 //dstp_a += dst_pitch;
439 maskp += mask_pitch;
440 }
441 }
442
443 if constexpr (!lumaonly) {
444 dstp_u += dst_pitchUV;
445 dstp_v += dst_pitchUV;
446 ovrp_u += overlay_pitchUV;
447 ovrp_v += overlay_pitchUV;
448 }
449 }
450
451 dst_pitch *= sizeof(float);
452 dst_pitchUV *= sizeof(float);
453 overlay_pitch *= sizeof(float);
454 overlay_pitchUV *= sizeof(float);
455 if constexpr (has_alpha)
456 mask_pitch *= sizeof(float);
457
458 // make luma
459 // recursively call the same function, but with lumaonly=true to update luma plane using the original chroma planes for decision
460 if constexpr (!lumaonly && maskMode != MASK444)
461 layer_yuv_lighten_darken_f_c<mode, MASK444, true /* lumaonly*/, has_alpha>(
462 dstp8, dstp8_u, dstp8_v, //dstp8_a,
463 ovrp8, ovrp8_u, ovrp8_v, maskp8,
464 dst_pitch, dst_pitchUV, overlay_pitch, overlay_pitchUV, mask_pitch,
465 width, height, opacity, thresh);
466 }
467
468 DISABLE_WARNING_POP
469
470 // Dispatchers
471
472 static void get_layer_yuv_lighten_darken_functions(bool isLighten, int placement, VideoInfo& vi, int bits_per_pixel,
473 /*out*/layer_yuv_lighten_darken_c_t** layer_fn,
474 /*out*/layer_yuv_lighten_darken_f_c_t** layer_f_fn)
475 {
476
477 #define YUV_LIGHTEN_DARKEN_DISPATCH(L_or_D, MaskType, lumaonly, has_alpha) \
478 { if (bits_per_pixel == 8) \
479 *layer_fn = layer_yuv_lighten_darken_c<L_or_D, MaskType, uint8_t, lumaonly /*lumaonly*/, has_alpha /*has_alpha*/>; \
480 else if (bits_per_pixel <= 16) \
481 *layer_fn = layer_yuv_lighten_darken_c<L_or_D, MaskType, uint16_t, lumaonly /*lumaonly*/, has_alpha /*has_alpha*/>; \
482 else /* float */ \
483 *layer_f_fn = layer_yuv_lighten_darken_f_c<L_or_D, MaskType, lumaonly /*lumaonly*/, has_alpha /*has_alpha*/>; \
484 }
485
486 // Note, that we always call one instance of the filter: the lumaonly==false version,
487 // since the filter handles U and V first, then recursively calls itself with lumaonly==true;
488 // the chroma part needs unaltered luma for decision, so we delay Y processing.
489 // Except Y-only greayscale input, where only luma plane exists.
490
491 if (isLighten) {
492
493 if (vi.IsYV411())
494 *layer_fn = layer_yuv_lighten_darken_c<LIGHTEN, MASK411, uint8_t, false /*lumaonly*/, false /*has_alpha*/>;
495 else if (vi.Is420())
496 {
497 if (placement == PLACEMENT_MPEG1)
498 YUV_LIGHTEN_DARKEN_DISPATCH(LIGHTEN, MASK420, false, false)
499 else if (placement == PLACEMENT_TOPLEFT)
500 YUV_LIGHTEN_DARKEN_DISPATCH(LIGHTEN, MASK420_TOPLEFT, false, false)
501 else
502 YUV_LIGHTEN_DARKEN_DISPATCH(LIGHTEN, MASK420_MPEG2, false, false)
503 // PLACEMENT_MPEG2
504 }
505 else if (vi.Is422())
506 {
507 if (placement == PLACEMENT_MPEG1)
508 YUV_LIGHTEN_DARKEN_DISPATCH(LIGHTEN, MASK422, false, false)
509 else if (placement == PLACEMENT_TOPLEFT)
510 YUV_LIGHTEN_DARKEN_DISPATCH(LIGHTEN, MASK422_TOPLEFT, false, false)
511 else
512 YUV_LIGHTEN_DARKEN_DISPATCH(LIGHTEN, MASK422_MPEG2, false, false)
513 // PLACEMENT_MPEG2
514 }
515 else if (vi.Is444())
516 YUV_LIGHTEN_DARKEN_DISPATCH(LIGHTEN, MASK444, false, false)
517 else if (vi.IsY())
518 YUV_LIGHTEN_DARKEN_DISPATCH(LIGHTEN, MASK444, true, false)
519 }
520 else {
521 // darken
522 if (vi.IsYV411())
523 *layer_fn = layer_yuv_lighten_darken_c<DARKEN, MASK411, uint8_t, false /*lumaonly*/, false /*has_alpha*/>;
524 else if (vi.Is420())
525 {
526 if (placement == PLACEMENT_MPEG1)
527 YUV_LIGHTEN_DARKEN_DISPATCH(DARKEN, MASK420, false, false)
528 else if (placement == PLACEMENT_TOPLEFT)
529 YUV_LIGHTEN_DARKEN_DISPATCH(DARKEN, MASK420_TOPLEFT, false, false)
530 else // PLACEMENT_MPEG2
531 YUV_LIGHTEN_DARKEN_DISPATCH(DARKEN, MASK420_MPEG2, false, false)
532 }
533 else if (vi.Is422())
534 {
535 if (placement == PLACEMENT_MPEG1)
536 YUV_LIGHTEN_DARKEN_DISPATCH(DARKEN, MASK422, false, false)
537 else if (placement == PLACEMENT_TOPLEFT)
538 YUV_LIGHTEN_DARKEN_DISPATCH(DARKEN, MASK422_TOPLEFT, false, false)
539 else // PLACEMENT_MPEG2
540 YUV_LIGHTEN_DARKEN_DISPATCH(DARKEN, MASK422_MPEG2, false, false)
541 }
542 else if (vi.Is444())
543 YUV_LIGHTEN_DARKEN_DISPATCH(DARKEN, MASK444, false, false)
544 else if (vi.IsY())
545 YUV_LIGHTEN_DARKEN_DISPATCH(DARKEN, MASK444, true, false)
546 }
547 #undef YUV_LIGHTEN_DARKEN_DISPATCH
548 }
549
550
551 3 static void get_layer_yuv_mul_functions(
552 bool is_chroma, bool hasAlpha,
553 int placement, VideoInfo& vi, int bits_per_pixel,
554 /*out*/layer_yuv_mul_c_t** layer_fn,
555 /*out*/layer_yuv_mul_f_c_t** layer_f_fn)
556 {
557 #define YUV_MUL_DISPATCH(MaskType, is_chroma, has_alpha) \
558 { if (bits_per_pixel == 8) \
559 *layer_fn = layer_yuv_mul_c<MaskType, uint8_t, is_chroma, has_alpha>; \
560 else if (bits_per_pixel < 16) \
561 *layer_fn = layer_yuv_mul_c<MaskType, uint16_t, is_chroma, has_alpha>; \
562 else if (bits_per_pixel == 16) \
563 *layer_fn = layer_yuv_mul_c<MaskType, uint16_t, is_chroma, has_alpha>; \
564 else /* float */ \
565 *layer_f_fn = layer_yuv_mul_f_c<MaskType, is_chroma, has_alpha>; \
566 }
567
568
2/2
✓ Branch 2 → 3 taken 2 times.
✓ Branch 2 → 121 taken 1 time.
3 if (is_chroma) // not luma channel
569 {
570
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 2 times.
2 if (vi.IsYV411())
571 {
572 // never has Alpha
573 *layer_fn = layer_yuv_mul_c<MASK411, uint8_t, true, false>;
574 }
575
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 55 taken 2 times.
2 else if (vi.Is420())
576 {
577 if (placement == PLACEMENT_MPEG1) {
578 if (hasAlpha) {
579 YUV_MUL_DISPATCH(MASK420, true, true)
580 }
581 else {
582 YUV_MUL_DISPATCH(MASK420, true, false)
583 }
584 }
585 else if (placement == PLACEMENT_TOPLEFT) {
586 if (hasAlpha) {
587 YUV_MUL_DISPATCH(MASK420_TOPLEFT, true, true)
588 }
589 else {
590 YUV_MUL_DISPATCH(MASK420_TOPLEFT, true, false)
591 }
592 }
593 else {
594 if (hasAlpha) {
595 YUV_MUL_DISPATCH(MASK420_MPEG2, true, true)
596 }
597 else {
598 YUV_MUL_DISPATCH(MASK420_MPEG2, true, false)
599 }
600 }
601 }
602
1/2
✗ Branch 56 → 57 not taken.
✓ Branch 56 → 104 taken 2 times.
2 else if (vi.Is422())
603 {
604 if (placement == PLACEMENT_MPEG1) {
605 if (hasAlpha) {
606 YUV_MUL_DISPATCH(MASK422, true, true)
607 }
608 else {
609 YUV_MUL_DISPATCH(MASK422, true, false)
610 }
611 }
612 else if (placement == PLACEMENT_TOPLEFT) {
613 if (hasAlpha) {
614 YUV_MUL_DISPATCH(MASK422_TOPLEFT, true, true)
615 }
616 else {
617 YUV_MUL_DISPATCH(MASK422_TOPLEFT, true, false)
618 }
619 }
620 else {
621 if (hasAlpha) {
622 YUV_MUL_DISPATCH(MASK422_MPEG2, true, true)
623 }
624 else {
625 YUV_MUL_DISPATCH(MASK422_MPEG2, true, false)
626 }
627 }
628 }
629
1/2
✓ Branch 105 → 106 taken 2 times.
✗ Branch 105 → 136 not taken.
2 else if (vi.Is444())
630 {
631
1/2
✗ Branch 106 → 107 not taken.
✓ Branch 106 → 114 taken 2 times.
2 if (hasAlpha) {
632 YUV_MUL_DISPATCH(MASK444, true, true)
633 }
634 else {
635
1/6
✓ Branch 114 → 115 taken 2 times.
✗ Branch 114 → 116 not taken.
✗ Branch 116 → 117 not taken.
✗ Branch 116 → 118 not taken.
✗ Branch 118 → 119 not taken.
✗ Branch 118 → 120 not taken.
2 YUV_MUL_DISPATCH(MASK444, true, false)
636 }
637 }
638 }
639 else // luma channel
640 {
641
1/2
✗ Branch 121 → 122 not taken.
✓ Branch 121 → 129 taken 1 time.
1 if (hasAlpha)
642 YUV_MUL_DISPATCH(MASK444, false, true)
643 else
644
1/6
✓ Branch 129 → 130 taken 1 time.
✗ Branch 129 → 131 not taken.
✗ Branch 131 → 132 not taken.
✗ Branch 131 → 133 not taken.
✗ Branch 133 → 134 not taken.
✗ Branch 133 → 135 not taken.
1 YUV_MUL_DISPATCH(MASK444, false, false)
645 }
646 #undef YUV_MUL_DISPATCH
647 3 }
648
649 // ---------------------------------------------------------------------------
650 // mulovr: Overlay-style multiply.
651 // Overlay luma (Y) drives the effect on all planes:
652 // darken_factor = alpha_eff * (max - ovr_Y) / max
653 // result_Y = base_Y * (max - darken_factor) / max
654 // result_UV = base_UV * (max - darken_factor) / max + half_pix * darken_factor / max
655 // For float (neutral UV = 0.0): result = base * (1 - alpha_eff * (1 - ovr_Y)) for all planes.
656 // Two-pass for subsampled formats (mirrors lighten/darken):
657 // Pass 1 (lumaonly=false): UV update using spatially-averaged overlay Y; MASK444 also does Y.
658 // Pass 2 (lumaonly=true, MASK444): Y-only update at full luma resolution.
659 // greyscale (vi.IsY()): dispatched directly as lumaonly=true — identical to Layer "Mul" luma.
660 // ---------------------------------------------------------------------------
661
662 template<MaskMode maskMode, typename pixel_t, bool lumaonly, bool has_alpha>
663 2 static void layer_yuv_mulovr_c(
664 BYTE* dstp8, BYTE* dstp8_u, BYTE* dstp8_v,
665 const BYTE* ovrp8,
666 const BYTE* maskp8,
667 int dst_pitch, int dst_pitchUV,
668 int overlay_pitch,
669 int mask_pitch,
670 int width, int height, int opacity_i, int bits_per_pixel)
671 {
672 2 pixel_t* dstp = reinterpret_cast<pixel_t*>(dstp8);
673 2 pixel_t* dstp_u = reinterpret_cast<pixel_t*>(dstp8_u); // nullptr when lumaonly
674 2 pixel_t* dstp_v = reinterpret_cast<pixel_t*>(dstp8_v); // nullptr when lumaonly
675 2 const pixel_t* ovrp = reinterpret_cast<const pixel_t*>(ovrp8);
676 2 const pixel_t* maskp = has_alpha ? reinterpret_cast<const pixel_t*>(maskp8) : nullptr;
677
678 2 dst_pitch /= sizeof(pixel_t);
679 2 dst_pitchUV /= sizeof(pixel_t);
680 2 overlay_pitch /= sizeof(pixel_t);
681 if constexpr (has_alpha)
682 1 mask_pitch /= sizeof(pixel_t);
683
684 if constexpr (sizeof(pixel_t) == 1)
685 2 bits_per_pixel = 8;
686
687 2 const MagicDiv magic = get_magic_div(bits_per_pixel);
688 2 const int max_pixel_value = (1 << bits_per_pixel) - 1;
689 2 const int half = max_pixel_value / 2; // rounding bias for magic_div
690 2 const uint32_t half_pix = (uint32_t)(max_pixel_value / 2); // integer chroma neutral
691
692 2 const int cwidth = (maskMode == MASK444) ? width : (maskMode == MASK411) ? width >> 2 : width >> 1;
693 2 const int cheight = (maskMode == MASK444 || maskMode == MASK422 || maskMode == MASK422_MPEG2 || maskMode == MASK422_TOPLEFT || maskMode == MASK411) ? height : height >> 1;
694
695 2 std::vector<pixel_t> ovr_y_buffer;
696 2 std::vector<pixel_t> mask_buffer;
697 if constexpr (maskMode != MASK444) {
698 ovr_y_buffer.resize(cwidth);
699 if constexpr (has_alpha)
700 mask_buffer.resize(cwidth);
701 }
702
703
4/136
void layer_yuv_mulovr_c<(MaskMode)0, unsigned char, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 18 → 7 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 26 → 7 not taken.
✗ Branch 26 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)0, unsigned short, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 18 → 7 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 26 → 7 not taken.
✗ Branch 26 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)1, unsigned char, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 18 → 7 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 26 → 7 not taken.
✗ Branch 26 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)1, unsigned char, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 22 → 8 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 38 → 8 not taken.
✗ Branch 38 → 39 not taken.
void layer_yuv_mulovr_c<(MaskMode)1, unsigned short, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 18 → 7 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 26 → 7 not taken.
✗ Branch 26 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)1, unsigned short, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 22 → 8 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 38 → 8 not taken.
✗ Branch 38 → 39 not taken.
void layer_yuv_mulovr_c<(MaskMode)2, unsigned char, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 18 → 7 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 26 → 7 not taken.
✗ Branch 26 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)2, unsigned char, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 22 → 8 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 38 → 8 not taken.
✗ Branch 38 → 39 not taken.
void layer_yuv_mulovr_c<(MaskMode)2, unsigned short, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 18 → 7 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 26 → 7 not taken.
✗ Branch 26 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)2, unsigned short, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 22 → 8 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 38 → 8 not taken.
✗ Branch 38 → 39 not taken.
void layer_yuv_mulovr_c<(MaskMode)3, unsigned char, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 18 → 7 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 26 → 7 not taken.
✗ Branch 26 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)3, unsigned char, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 22 → 8 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 38 → 8 not taken.
✗ Branch 38 → 39 not taken.
void layer_yuv_mulovr_c<(MaskMode)3, unsigned short, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 18 → 7 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 26 → 7 not taken.
✗ Branch 26 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)3, unsigned short, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 22 → 8 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 38 → 8 not taken.
✗ Branch 38 → 39 not taken.
void layer_yuv_mulovr_c<(MaskMode)4, unsigned char, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 18 → 7 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 26 → 7 not taken.
✗ Branch 26 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)4, unsigned char, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 22 → 8 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 38 → 8 not taken.
✗ Branch 38 → 39 not taken.
void layer_yuv_mulovr_c<(MaskMode)4, unsigned short, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 18 → 7 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 26 → 7 not taken.
✗ Branch 26 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)4, unsigned short, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 22 → 8 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 38 → 8 not taken.
✗ Branch 38 → 39 not taken.
void layer_yuv_mulovr_c<(MaskMode)5, unsigned char, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 18 → 7 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 26 → 7 not taken.
✗ Branch 26 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)5, unsigned char, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 22 → 8 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 38 → 8 not taken.
✗ Branch 38 → 39 not taken.
void layer_yuv_mulovr_c<(MaskMode)5, unsigned short, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 18 → 7 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 26 → 7 not taken.
✗ Branch 26 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)5, unsigned short, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 22 → 8 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 38 → 8 not taken.
✗ Branch 38 → 39 not taken.
void layer_yuv_mulovr_c<(MaskMode)6, unsigned char, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 18 → 7 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 26 → 7 not taken.
✗ Branch 26 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)6, unsigned char, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 22 → 8 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 38 → 8 not taken.
✗ Branch 38 → 39 not taken.
void layer_yuv_mulovr_c<(MaskMode)6, unsigned short, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 18 → 7 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 26 → 7 not taken.
✗ Branch 26 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)6, unsigned short, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 22 → 8 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 38 → 8 not taken.
✗ Branch 38 → 39 not taken.
void layer_yuv_mulovr_c<(MaskMode)7, unsigned char, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 19 → 6 not taken.
✗ Branch 19 → 20 not taken.
✓ Branch 20 → 6 taken 2 times.
✓ Branch 20 → 21 taken 1 time.
void layer_yuv_mulovr_c<(MaskMode)7, unsigned char, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 22 → 6 not taken.
✗ Branch 22 → 23 not taken.
✓ Branch 24 → 6 taken 2 times.
✓ Branch 24 → 25 taken 1 time.
void layer_yuv_mulovr_c<(MaskMode)7, unsigned char, true, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 15 → 6 not taken.
✗ Branch 15 → 16 not taken.
✗ Branch 16 → 6 not taken.
✗ Branch 16 → 17 not taken.
void layer_yuv_mulovr_c<(MaskMode)7, unsigned char, true, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 18 → 6 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 20 → 6 not taken.
✗ Branch 20 → 21 not taken.
void layer_yuv_mulovr_c<(MaskMode)7, unsigned short, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 19 → 6 not taken.
✗ Branch 19 → 20 not taken.
✗ Branch 20 → 6 not taken.
✗ Branch 20 → 21 not taken.
void layer_yuv_mulovr_c<(MaskMode)7, unsigned short, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 22 → 6 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 24 → 6 not taken.
✗ Branch 24 → 25 not taken.
void layer_yuv_mulovr_c<(MaskMode)7, unsigned short, true, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 15 → 6 not taken.
✗ Branch 15 → 16 not taken.
✗ Branch 16 → 6 not taken.
✗ Branch 16 → 17 not taken.
void layer_yuv_mulovr_c<(MaskMode)7, unsigned short, true, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 18 → 6 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 20 → 6 not taken.
✗ Branch 20 → 21 not taken.
6 for (int y = 0; y < cheight; ++y) {
704 // Spatially average overlay Y to chroma resolution (full_opacity=true: no opacity baking).
705
0/68
void layer_yuv_mulovr_c<(MaskMode)0, unsigned char, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 23 not taken.
void layer_yuv_mulovr_c<(MaskMode)0, unsigned short, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 23 not taken.
void layer_yuv_mulovr_c<(MaskMode)1, unsigned char, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 23 not taken.
void layer_yuv_mulovr_c<(MaskMode)1, unsigned char, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)1, unsigned short, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 23 not taken.
void layer_yuv_mulovr_c<(MaskMode)1, unsigned short, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)2, unsigned char, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 23 not taken.
void layer_yuv_mulovr_c<(MaskMode)2, unsigned char, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)2, unsigned short, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 23 not taken.
void layer_yuv_mulovr_c<(MaskMode)2, unsigned short, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)3, unsigned char, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 23 not taken.
void layer_yuv_mulovr_c<(MaskMode)3, unsigned char, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)3, unsigned short, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 23 not taken.
void layer_yuv_mulovr_c<(MaskMode)3, unsigned short, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)4, unsigned char, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 23 not taken.
void layer_yuv_mulovr_c<(MaskMode)4, unsigned char, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)4, unsigned short, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 23 not taken.
void layer_yuv_mulovr_c<(MaskMode)4, unsigned short, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)5, unsigned char, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 23 not taken.
void layer_yuv_mulovr_c<(MaskMode)5, unsigned char, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)5, unsigned short, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 23 not taken.
void layer_yuv_mulovr_c<(MaskMode)5, unsigned short, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)6, unsigned char, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 23 not taken.
void layer_yuv_mulovr_c<(MaskMode)6, unsigned char, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)6, unsigned short, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 23 not taken.
void layer_yuv_mulovr_c<(MaskMode)6, unsigned short, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)7, unsigned char, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 23 not taken.
void layer_yuv_mulovr_c<(MaskMode)7, unsigned char, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 26 not taken.
void layer_yuv_mulovr_c<(MaskMode)7, unsigned char, true, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 19 not taken.
void layer_yuv_mulovr_c<(MaskMode)7, unsigned char, true, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 22 not taken.
void layer_yuv_mulovr_c<(MaskMode)7, unsigned short, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 23 not taken.
void layer_yuv_mulovr_c<(MaskMode)7, unsigned short, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 26 not taken.
void layer_yuv_mulovr_c<(MaskMode)7, unsigned short, true, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 19 not taken.
void layer_yuv_mulovr_c<(MaskMode)7, unsigned short, true, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 22 not taken.
4 const pixel_t* ovr_y_ptr = LAYER_ROWPREP_FN<maskMode, pixel_t, true>(ovrp, overlay_pitch, cwidth, ovr_y_buffer);
706 4 const pixel_t* mask_ptr = nullptr;
707 if constexpr (has_alpha)
708
0/32
void layer_yuv_mulovr_c<(MaskMode)1, unsigned char, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)1, unsigned short, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)2, unsigned char, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)2, unsigned short, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)3, unsigned char, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)3, unsigned short, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)4, unsigned char, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)4, unsigned short, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)5, unsigned char, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)5, unsigned short, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)6, unsigned char, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)6, unsigned short, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 27 not taken.
void layer_yuv_mulovr_c<(MaskMode)7, unsigned char, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 26 not taken.
void layer_yuv_mulovr_c<(MaskMode)7, unsigned char, true, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 22 not taken.
void layer_yuv_mulovr_c<(MaskMode)7, unsigned short, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 26 not taken.
void layer_yuv_mulovr_c<(MaskMode)7, unsigned short, true, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 22 not taken.
2 mask_ptr = LAYER_ROWPREP_FN<maskMode, pixel_t, true>(maskp, mask_pitch, cwidth, mask_buffer);
709
710
4/136
void layer_yuv_mulovr_c<(MaskMode)0, unsigned char, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 16 → 9 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 24 → 17 not taken.
✗ Branch 24 → 25 not taken.
void layer_yuv_mulovr_c<(MaskMode)0, unsigned short, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 16 → 9 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 24 → 17 not taken.
✗ Branch 24 → 25 not taken.
void layer_yuv_mulovr_c<(MaskMode)1, unsigned char, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 16 → 9 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 24 → 17 not taken.
✗ Branch 24 → 25 not taken.
void layer_yuv_mulovr_c<(MaskMode)1, unsigned char, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 20 → 11 not taken.
✗ Branch 20 → 21 not taken.
✗ Branch 36 → 27 not taken.
✗ Branch 36 → 37 not taken.
void layer_yuv_mulovr_c<(MaskMode)1, unsigned short, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 16 → 9 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 24 → 17 not taken.
✗ Branch 24 → 25 not taken.
void layer_yuv_mulovr_c<(MaskMode)1, unsigned short, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 20 → 11 not taken.
✗ Branch 20 → 21 not taken.
✗ Branch 36 → 27 not taken.
✗ Branch 36 → 37 not taken.
void layer_yuv_mulovr_c<(MaskMode)2, unsigned char, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 16 → 9 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 24 → 17 not taken.
✗ Branch 24 → 25 not taken.
void layer_yuv_mulovr_c<(MaskMode)2, unsigned char, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 20 → 11 not taken.
✗ Branch 20 → 21 not taken.
✗ Branch 36 → 27 not taken.
✗ Branch 36 → 37 not taken.
void layer_yuv_mulovr_c<(MaskMode)2, unsigned short, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 16 → 9 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 24 → 17 not taken.
✗ Branch 24 → 25 not taken.
void layer_yuv_mulovr_c<(MaskMode)2, unsigned short, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 20 → 11 not taken.
✗ Branch 20 → 21 not taken.
✗ Branch 36 → 27 not taken.
✗ Branch 36 → 37 not taken.
void layer_yuv_mulovr_c<(MaskMode)3, unsigned char, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 16 → 9 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 24 → 17 not taken.
✗ Branch 24 → 25 not taken.
void layer_yuv_mulovr_c<(MaskMode)3, unsigned char, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 20 → 11 not taken.
✗ Branch 20 → 21 not taken.
✗ Branch 36 → 27 not taken.
✗ Branch 36 → 37 not taken.
void layer_yuv_mulovr_c<(MaskMode)3, unsigned short, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 16 → 9 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 24 → 17 not taken.
✗ Branch 24 → 25 not taken.
void layer_yuv_mulovr_c<(MaskMode)3, unsigned short, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 20 → 11 not taken.
✗ Branch 20 → 21 not taken.
✗ Branch 36 → 27 not taken.
✗ Branch 36 → 37 not taken.
void layer_yuv_mulovr_c<(MaskMode)4, unsigned char, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 16 → 9 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 24 → 17 not taken.
✗ Branch 24 → 25 not taken.
void layer_yuv_mulovr_c<(MaskMode)4, unsigned char, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 20 → 11 not taken.
✗ Branch 20 → 21 not taken.
✗ Branch 36 → 27 not taken.
✗ Branch 36 → 37 not taken.
void layer_yuv_mulovr_c<(MaskMode)4, unsigned short, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 16 → 9 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 24 → 17 not taken.
✗ Branch 24 → 25 not taken.
void layer_yuv_mulovr_c<(MaskMode)4, unsigned short, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 20 → 11 not taken.
✗ Branch 20 → 21 not taken.
✗ Branch 36 → 27 not taken.
✗ Branch 36 → 37 not taken.
void layer_yuv_mulovr_c<(MaskMode)5, unsigned char, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 16 → 9 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 24 → 17 not taken.
✗ Branch 24 → 25 not taken.
void layer_yuv_mulovr_c<(MaskMode)5, unsigned char, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 20 → 11 not taken.
✗ Branch 20 → 21 not taken.
✗ Branch 36 → 27 not taken.
✗ Branch 36 → 37 not taken.
void layer_yuv_mulovr_c<(MaskMode)5, unsigned short, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 16 → 9 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 24 → 17 not taken.
✗ Branch 24 → 25 not taken.
void layer_yuv_mulovr_c<(MaskMode)5, unsigned short, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 20 → 11 not taken.
✗ Branch 20 → 21 not taken.
✗ Branch 36 → 27 not taken.
✗ Branch 36 → 37 not taken.
void layer_yuv_mulovr_c<(MaskMode)6, unsigned char, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 16 → 9 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 24 → 17 not taken.
✗ Branch 24 → 25 not taken.
void layer_yuv_mulovr_c<(MaskMode)6, unsigned char, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 20 → 11 not taken.
✗ Branch 20 → 21 not taken.
✗ Branch 36 → 27 not taken.
✗ Branch 36 → 37 not taken.
void layer_yuv_mulovr_c<(MaskMode)6, unsigned short, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 16 → 9 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 24 → 17 not taken.
✗ Branch 24 → 25 not taken.
void layer_yuv_mulovr_c<(MaskMode)6, unsigned short, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 20 → 11 not taken.
✗ Branch 20 → 21 not taken.
✗ Branch 36 → 27 not taken.
✗ Branch 36 → 37 not taken.
void layer_yuv_mulovr_c<(MaskMode)7, unsigned char, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 17 → 8 not taken.
✗ Branch 17 → 18 not taken.
✓ Branch 18 → 9 taken 10 times.
✓ Branch 18 → 19 taken 2 times.
void layer_yuv_mulovr_c<(MaskMode)7, unsigned char, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 20 → 9 not taken.
✗ Branch 20 → 21 not taken.
✓ Branch 22 → 11 taken 10 times.
✓ Branch 22 → 23 taken 2 times.
void layer_yuv_mulovr_c<(MaskMode)7, unsigned char, true, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 13 → 8 not taken.
✗ Branch 13 → 14 not taken.
✗ Branch 14 → 9 not taken.
✗ Branch 14 → 15 not taken.
void layer_yuv_mulovr_c<(MaskMode)7, unsigned char, true, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 16 → 9 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 18 → 11 not taken.
✗ Branch 18 → 19 not taken.
void layer_yuv_mulovr_c<(MaskMode)7, unsigned short, false, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 17 → 8 not taken.
✗ Branch 17 → 18 not taken.
✗ Branch 18 → 9 not taken.
✗ Branch 18 → 19 not taken.
void layer_yuv_mulovr_c<(MaskMode)7, unsigned short, false, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 20 → 9 not taken.
✗ Branch 20 → 21 not taken.
✗ Branch 22 → 11 not taken.
✗ Branch 22 → 23 not taken.
void layer_yuv_mulovr_c<(MaskMode)7, unsigned short, true, false>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 13 → 8 not taken.
✗ Branch 13 → 14 not taken.
✗ Branch 14 → 9 not taken.
✗ Branch 14 → 15 not taken.
void layer_yuv_mulovr_c<(MaskMode)7, unsigned short, true, true>(unsigned char*, unsigned char*, unsigned char*, unsigned char const*, unsigned char const*, int, int, int, int, int, int, int, int):
✗ Branch 16 → 9 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 18 → 11 not taken.
✗ Branch 18 → 19 not taken.
24 for (int x = 0; x < cwidth; ++x) {
711 20 const uint32_t alpha_eff = has_alpha
712 10 ? magic_div_rt<pixel_t>((uint32_t)mask_ptr[x] * opacity_i + half, magic)
713 : (uint32_t)opacity_i;
714 // dark overlay Y → large darken_factor → strong pull toward neutral/black.
715 20 const uint32_t darken_factor = magic_div_rt<pixel_t>(alpha_eff * ((uint32_t)max_pixel_value - (uint32_t)ovr_y_ptr[x]) + half, magic);
716 20 const uint32_t inv_keep = (uint32_t)max_pixel_value - darken_factor;
717
718 if constexpr (!lumaonly) {
719 // UV: pull toward half_pix (chroma neutral). Overflow-safe in uint32 (see plan).
720 20 dstp_u[x] = (pixel_t)magic_div_rt<pixel_t>((uint32_t)dstp_u[x] * inv_keep + half_pix * darken_factor + half, magic);
721 20 dstp_v[x] = (pixel_t)magic_div_rt<pixel_t>((uint32_t)dstp_v[x] * inv_keep + half_pix * darken_factor + half, magic);
722 }
723 // For MASK444, luma and chroma share resolution — update Y here.
724 if constexpr (maskMode == MASK444)
725 40 dstp[x] = (pixel_t)magic_div_rt<pixel_t>((uint32_t)dstp[x] * inv_keep + half, magic);
726 }
727
728 if constexpr (maskMode == MASK420 || maskMode == MASK420_MPEG2 || maskMode == MASK420_TOPLEFT) {
729 dstp += dst_pitch * 2;
730 ovrp += overlay_pitch * 2;
731 if constexpr (has_alpha)
732 maskp += mask_pitch * 2;
733 }
734 else {
735 4 dstp += dst_pitch;
736 4 ovrp += overlay_pitch;
737 if constexpr (has_alpha)
738 2 maskp += mask_pitch;
739 }
740
741 if constexpr (!lumaonly) {
742 4 dstp_u += dst_pitchUV;
743 4 dstp_v += dst_pitchUV;
744 }
745 }
746
747 2 dst_pitch *= sizeof(pixel_t);
748 2 dst_pitchUV *= sizeof(pixel_t);
749 2 overlay_pitch *= sizeof(pixel_t);
750 if constexpr (has_alpha)
751 1 mask_pitch *= sizeof(pixel_t);
752
753 // Phase 2: luma-only pass at full luma resolution.
754 if constexpr (!lumaonly && maskMode != MASK444)
755 layer_yuv_mulovr_c<MASK444, pixel_t, true, has_alpha>(
756 dstp8, nullptr, nullptr,
757 ovrp8, maskp8,
758 dst_pitch, 0, overlay_pitch, mask_pitch,
759 width, height, opacity_i, bits_per_pixel);
760 2 }
761
762 // Float version — neutral UV = 0.0f in AviSynth+ float YUV, so both luma and chroma
763 // collapse to the same formula: result = base * (1 - alpha_eff * (1 - ovr_Y)).
764 template<MaskMode maskMode, bool lumaonly, bool has_alpha>
765 static void layer_yuv_mulovr_f_c(
766 BYTE* dstp8, BYTE* dstp8_u, BYTE* dstp8_v,
767 const BYTE* ovrp8,
768 const BYTE* maskp8,
769 int dst_pitch, int dst_pitchUV,
770 int overlay_pitch,
771 int mask_pitch,
772 int width, int height, float opacity)
773 {
774 float* dstp = reinterpret_cast<float*>(dstp8);
775 float* dstp_u = reinterpret_cast<float*>(dstp8_u); // nullptr when lumaonly
776 float* dstp_v = reinterpret_cast<float*>(dstp8_v); // nullptr when lumaonly
777 const float* ovrp = reinterpret_cast<const float*>(ovrp8);
778 const float* maskp = has_alpha ? reinterpret_cast<const float*>(maskp8) : nullptr;
779
780 dst_pitch /= sizeof(float);
781 dst_pitchUV /= sizeof(float);
782 overlay_pitch /= sizeof(float);
783 if constexpr (has_alpha)
784 mask_pitch /= sizeof(float);
785
786 const int cwidth = (maskMode == MASK444) ? width : (maskMode == MASK411) ? width >> 2 : width >> 1;
787 const int cheight = (maskMode == MASK444 || maskMode == MASK422 || maskMode == MASK422_MPEG2 || maskMode == MASK422_TOPLEFT || maskMode == MASK411) ? height : height >> 1;
788
789 std::vector<float> ovr_y_buffer;
790 std::vector<float> mask_buffer;
791 if constexpr (maskMode != MASK444) {
792 ovr_y_buffer.resize(cwidth);
793 if constexpr (has_alpha)
794 mask_buffer.resize(cwidth);
795 }
796
797 for (int y = 0; y < cheight; ++y) {
798 const float* ovr_y_ptr = prepare_effective_mask_for_row_float_c<maskMode>(ovrp, overlay_pitch, cwidth, ovr_y_buffer);
799 const float* mask_ptr = nullptr;
800 if constexpr (has_alpha)
801 mask_ptr = prepare_effective_mask_for_row_float_c<maskMode>(maskp, mask_pitch, cwidth, mask_buffer);
802
803 for (int x = 0; x < cwidth; ++x) {
804 const float alpha_eff = has_alpha ? mask_ptr[x] * opacity : opacity;
805 const float inv_keep = 1.0f - alpha_eff * (1.0f - ovr_y_ptr[x]);
806
807 if constexpr (!lumaonly) {
808 dstp_u[x] *= inv_keep; // neutral UV = 0.0f → same formula as luma
809 dstp_v[x] *= inv_keep;
810 }
811 if constexpr (maskMode == MASK444)
812 dstp[x] *= inv_keep;
813 }
814
815 if constexpr (maskMode == MASK420 || maskMode == MASK420_MPEG2 || maskMode == MASK420_TOPLEFT) {
816 dstp += dst_pitch * 2;
817 ovrp += overlay_pitch * 2;
818 if constexpr (has_alpha)
819 maskp += mask_pitch * 2;
820 }
821 else {
822 dstp += dst_pitch;
823 ovrp += overlay_pitch;
824 if constexpr (has_alpha)
825 maskp += mask_pitch;
826 }
827
828 if constexpr (!lumaonly) {
829 dstp_u += dst_pitchUV;
830 dstp_v += dst_pitchUV;
831 }
832 }
833
834 dst_pitch *= sizeof(float);
835 dst_pitchUV *= sizeof(float);
836 overlay_pitch *= sizeof(float);
837 if constexpr (has_alpha)
838 mask_pitch *= sizeof(float);
839
840 if constexpr (!lumaonly && maskMode != MASK444)
841 layer_yuv_mulovr_f_c<MASK444, true, has_alpha>(
842 dstp8, nullptr, nullptr,
843 ovrp8, maskp8,
844 dst_pitch, 0, overlay_pitch, mask_pitch,
845 width, height, opacity);
846 }
847
848 2 static void get_layer_yuv_mulovr_functions(
849 bool has_alpha, int placement, VideoInfo& vi, int bits_per_pixel,
850 layer_yuv_mulovr_c_t** layer_fn,
851 layer_yuv_mulovr_f_c_t** layer_f_fn)
852 {
853 #define MULOVR_DISPATCH(MaskType, lumaonly, ha) \
854 { if (bits_per_pixel == 8) \
855 *layer_fn = layer_yuv_mulovr_c <MaskType, uint8_t, lumaonly, ha>; \
856 else if (bits_per_pixel <= 16) \
857 *layer_fn = layer_yuv_mulovr_c <MaskType, uint16_t, lumaonly, ha>; \
858 else \
859 *layer_f_fn = layer_yuv_mulovr_f_c<MaskType, lumaonly, ha>; \
860 }
861
862 #define MULOVR_HA(MaskType, lumaonly) \
863 { if (has_alpha) { MULOVR_DISPATCH(MaskType, lumaonly, true) } \
864 else { MULOVR_DISPATCH(MaskType, lumaonly, false) } }
865
866
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 15 taken 2 times.
2 if (vi.IsY()) {
867 // Greyscale: no UV planes — luma-only pass, identical to Layer "Mul" luma.
868 MULOVR_HA(MASK444, true)
869 }
870
1/2
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 22 taken 2 times.
2 else if (vi.IsYV411()) {
871 MULOVR_DISPATCH(MASK411, false, false) // YV411 never has alpha
872 }
873
1/2
✗ Branch 23 → 24 not taken.
✓ Branch 23 → 59 taken 2 times.
2 else if (vi.Is420()) {
874 if (placement == PLACEMENT_MPEG1) { MULOVR_HA(MASK420, false) }
875 else if (placement == PLACEMENT_TOPLEFT) { MULOVR_HA(MASK420_TOPLEFT, false) }
876 else { MULOVR_HA(MASK420_MPEG2, false) }
877 }
878
1/2
✗ Branch 60 → 61 not taken.
✓ Branch 60 → 96 taken 2 times.
2 else if (vi.Is422()) {
879 if (placement == PLACEMENT_MPEG1) { MULOVR_HA(MASK422, false) }
880 else if (placement == PLACEMENT_TOPLEFT) { MULOVR_HA(MASK422_TOPLEFT, false) }
881 else { MULOVR_HA(MASK422_MPEG2, false) }
882 }
883 else { // Is444() — cwidth == width, cheight == height; same-res, single pass
884
4/10
✓ Branch 96 → 97 taken 1 time.
✓ Branch 96 → 102 taken 1 time.
✓ Branch 97 → 98 taken 1 time.
✗ Branch 97 → 99 not taken.
✗ Branch 99 → 100 not taken.
✗ Branch 99 → 101 not taken.
✓ Branch 102 → 103 taken 1 time.
✗ Branch 102 → 104 not taken.
✗ Branch 104 → 105 not taken.
✗ Branch 104 → 106 not taken.
2 MULOVR_HA(MASK444, false)
885 }
886
887 #undef MULOVR_HA
888 #undef MULOVR_DISPATCH
889 2 }
890
891 // both masked merge (HasAlpha) and plain add (no alpha)
892 // Though we use it only for masked merge, kept for reference.
893 static void get_layer_yuv_add_masked_functions(
894 bool is_chroma, bool hasAlpha,
895 int placement, VideoInfo& vi, int bits_per_pixel,
896 /*out*/masked_merge_fn_t** layer_fn,
897 /*out*/masked_merge_float_fn_t** layer_f_fn)
898 {
899 // Use the unified (Layer,Overlay) masked merge functions
900 // Determine MaskMode from format and placement
901 MaskMode maskMode = MASK444;
902 if (is_chroma) {
903 if (vi.IsYV411())
904 maskMode = MASK411;
905 else if (vi.Is420())
906 maskMode = (placement == PLACEMENT_MPEG1) ? MASK420 : (placement == PLACEMENT_TOPLEFT) ? MASK420_TOPLEFT : MASK420_MPEG2;
907 else if (vi.Is422())
908 maskMode = (placement == PLACEMENT_MPEG1) ? MASK422 : (placement == PLACEMENT_TOPLEFT) ? MASK422_TOPLEFT : MASK422_MPEG2;
909 // Is444() / IsY(): stay MASK444
910 }
911 // is_chroma=false (luma): always MASK444
912 *layer_fn = get_overlay_blend_masked_fn_c(is_chroma, maskMode);
913 *layer_f_fn = get_overlay_blend_masked_float_fn_c(is_chroma, maskMode);
914
915 }
916
917 /* planar rgb */
918 template<int mode, typename pixel_t, bool has_alpha, bool blend_alpha>
919 static void layer_planarrgb_lighten_darken_c(BYTE** dstp8, const BYTE** ovrp8, const BYTE* maskp8, int dst_pitch, int overlay_pitch, int mask_pitch, int width, int height, int opacity_i, int thresh, int bits_per_pixel) {
920 pixel_t* dstp_g = reinterpret_cast<pixel_t*>(dstp8[0]);
921 pixel_t* dstp_b = reinterpret_cast<pixel_t*>(dstp8[1]);
922 pixel_t* dstp_r = reinterpret_cast<pixel_t*>(dstp8[2]);
923 // dstp8[3]: written only when blend_alpha=true (both clips have alpha).
924 pixel_t* dstp_a;
925 if constexpr (blend_alpha)
926 dstp_a = reinterpret_cast<pixel_t*>(dstp8[3]);
927 const pixel_t* ovrp_g = reinterpret_cast<const pixel_t*>(ovrp8[0]);
928 const pixel_t* ovrp_b = reinterpret_cast<const pixel_t*>(ovrp8[1]);
929 const pixel_t* ovrp_r = reinterpret_cast<const pixel_t*>(ovrp8[2]);
930 // maskp: per-pixel blend weight — decoupled from ovrp8[3] so a future mask clip can be wired in.
931 const pixel_t* maskp = reinterpret_cast<const pixel_t*>(maskp8);
932 // alpha_target: value blended into dstp_a (only used when blend_alpha=true).
933 // For plain Add this is the same plane as maskp; for Subtract it is the inverted A plane.
934 const pixel_t* alpha_target;
935 if constexpr (blend_alpha)
936 alpha_target = reinterpret_cast<const pixel_t*>(ovrp8[3]);
937
938 dst_pitch /= sizeof(pixel_t);
939 overlay_pitch /= sizeof(pixel_t);
940 mask_pitch /= sizeof(pixel_t);
941
942 if constexpr (sizeof(pixel_t) == 1)
943 bits_per_pixel = 8; // make quasi constexpr
944
945 const MagicDiv magic = get_magic_div(bits_per_pixel);
946 const int max_pixel_value = (1 << bits_per_pixel) - 1;
947 const int half = max_pixel_value / 2;
948
949 for (int y = 0; y < height; ++y) {
950 for (int x = 0; x < width; ++x) {
951 // opacity_i is in [0..max_pixel_value], the same convention as masked_merge.
952 uint32_t alpha_eff;
953 if constexpr (has_alpha) {
954 const uint32_t alpha_src = (uint32_t)maskp[x];
955 alpha_eff = (uint32_t)magic_div_rt<pixel_t>(alpha_src * (uint32_t)opacity_i + half, magic);
956 } else {
957 alpha_eff = opacity_i;
958 }
959 // standard rgb->luma coefficients, scaled up by 15 bits
960 // no rounding, not really needed here
961 const int luma_ovr = (cyb * ovrp_b[x] + cyg * ovrp_g[x] + cyr * ovrp_r[x]) >> 15;
962 const int luma_src = (cyb * dstp_b[x] + cyg * dstp_g[x] + cyr * dstp_r[x]) >> 15;
963
964
965 if constexpr (mode == LIGHTEN)
966 alpha_eff = luma_ovr > luma_src + thresh ? alpha_eff : 0;
967 else // DARKEN
968 alpha_eff = luma_ovr < luma_src - thresh ? alpha_eff : 0;
969
970 const uint32_t inv_alpha = max_pixel_value - alpha_eff;
971
972 // move to magicdiv
973 //dstp_r[x] = (pixel_t)(dstp_r[x] + (((ovrp_r[x] - dstp_r[x]) * alpha + rounder) >> bits_per_pixel));
974 //dstp_g[x] = (pixel_t)(dstp_g[x] + (((ovrp_g[x] - dstp_g[x]) * alpha + rounder) >> bits_per_pixel));
975 //dstp_b[x] = (pixel_t)(dstp_b[x] + (((ovrp_b[x] - dstp_b[x]) * alpha + rounder) >> bits_per_pixel));
976 dstp_r[x] = (pixel_t)magic_div_rt<pixel_t>((uint32_t)dstp_r[x] * inv_alpha + (uint32_t)ovrp_r[x] * alpha_eff + half, magic);
977 dstp_g[x] = (pixel_t)magic_div_rt<pixel_t>((uint32_t)dstp_g[x] * inv_alpha + (uint32_t)ovrp_g[x] * alpha_eff + half, magic);
978 dstp_b[x] = (pixel_t)magic_div_rt<pixel_t>((uint32_t)dstp_b[x] * inv_alpha + (uint32_t)ovrp_b[x] * alpha_eff + half, magic);
979 if constexpr (blend_alpha)
980 dstp_a[x] = (pixel_t)magic_div_rt<pixel_t>((uint32_t)dstp_a[x] * inv_alpha + (uint32_t)alpha_target[x] * alpha_eff + half, magic);
981 }
982 dstp_g += dst_pitch;
983 dstp_b += dst_pitch;
984 dstp_r += dst_pitch;
985 if constexpr (blend_alpha)
986 dstp_a += dst_pitch;
987 ovrp_g += overlay_pitch;
988 ovrp_b += overlay_pitch;
989 ovrp_r += overlay_pitch;
990 if constexpr (has_alpha)
991 maskp += mask_pitch;
992 if constexpr (blend_alpha)
993 alpha_target += overlay_pitch;
994 }
995 }
996
997 template<int mode, bool has_alpha, bool blend_alpha>
998 static void layer_planarrgb_lighten_darken_f_c(BYTE** dstp8, const BYTE** ovrp8, const BYTE* maskp8, int dst_pitch, int overlay_pitch, int mask_pitch, int width, int height, float opacity, float thresh) {
999 float* dstp_g = reinterpret_cast<float*>(dstp8[0]);
1000 float* dstp_b = reinterpret_cast<float*>(dstp8[1]);
1001 float* dstp_r = reinterpret_cast<float*>(dstp8[2]);
1002 // dstp8[3]: written only when blend_alpha=true (both clips have alpha).
1003 float* dstp_a;
1004 if constexpr (blend_alpha)
1005 dstp_a = reinterpret_cast<float*>(dstp8[3]);
1006 const float* ovrp_g = reinterpret_cast<const float*>(ovrp8[0]);
1007 const float* ovrp_b = reinterpret_cast<const float*>(ovrp8[1]);
1008 const float* ovrp_r = reinterpret_cast<const float*>(ovrp8[2]);
1009 // maskp: per-pixel blend weight — decoupled from ovrp8[3].
1010 const float* maskp = reinterpret_cast<const float*>(maskp8);
1011 const float* alpha_target;
1012 if constexpr (blend_alpha)
1013 alpha_target = reinterpret_cast<const float*>(ovrp8[3]);
1014
1015 dst_pitch /= sizeof(float);
1016 overlay_pitch /= sizeof(float);
1017 mask_pitch /= sizeof(float);
1018
1019 for (int y = 0; y < height; ++y) {
1020 for (int x = 0; x < width; ++x) {
1021 float alpha = has_alpha ? maskp[x] * opacity : opacity;
1022
1023 float luma_ovr = cyb_f * ovrp_b[x] + cyg_f * ovrp_g[x] + cyr_f * ovrp_r[x];
1024 float luma_src = cyb_f * dstp_b[x] + cyg_f * dstp_g[x] + cyr_f * dstp_r[x];
1025
1026 if constexpr (mode == LIGHTEN)
1027 alpha = luma_ovr > luma_src + thresh ? alpha : 0;
1028 else // DARKEN
1029 alpha = luma_ovr < luma_src - thresh ? alpha : 0;
1030
1031 dstp_r[x] = dstp_r[x] + (ovrp_r[x] - dstp_r[x]) * alpha;
1032 dstp_g[x] = dstp_g[x] + (ovrp_g[x] - dstp_g[x]) * alpha;
1033 dstp_b[x] = dstp_b[x] + (ovrp_b[x] - dstp_b[x]) * alpha;
1034 if constexpr (blend_alpha)
1035 dstp_a[x] = dstp_a[x] + (alpha_target[x] - dstp_a[x]) * alpha;
1036 }
1037 dstp_g += dst_pitch;
1038 dstp_b += dst_pitch;
1039 dstp_r += dst_pitch;
1040 if constexpr (blend_alpha)
1041 dstp_a += dst_pitch;
1042 ovrp_g += overlay_pitch;
1043 ovrp_b += overlay_pitch;
1044 ovrp_r += overlay_pitch;
1045 if constexpr (has_alpha)
1046 maskp += mask_pitch;
1047 if constexpr (blend_alpha)
1048 alpha_target += overlay_pitch;
1049 }
1050 }
1051
1052
1053 static void get_layer_planarrgb_lighten_darken_functions(bool isLighten, bool hasAlpha, bool blendAlpha, int bits_per_pixel, /*out*/layer_planarrgb_lighten_darken_c_t** layer_fn, /*out*/layer_planarrgb_lighten_darken_f_c_t** layer_f_fn) {
1054
1055 #define PLANARRGB_LD_DISPATCH(LorD, has_alpha, blend_alpha) \
1056 { if (bits_per_pixel == 8) \
1057 *layer_fn = layer_planarrgb_lighten_darken_c<LorD, uint8_t, has_alpha, blend_alpha>; \
1058 else if (bits_per_pixel <= 16) \
1059 *layer_fn = layer_planarrgb_lighten_darken_c<LorD, uint16_t, has_alpha, blend_alpha>; \
1060 else /* float */ \
1061 *layer_f_fn = layer_planarrgb_lighten_darken_f_c<LorD, has_alpha, blend_alpha>; \
1062 }
1063
1064 if (isLighten) {
1065 if (hasAlpha) {
1066 if (blendAlpha) { PLANARRGB_LD_DISPATCH(LIGHTEN, true, true) }
1067 else { PLANARRGB_LD_DISPATCH(LIGHTEN, true, false) }
1068 }
1069 else {
1070 PLANARRGB_LD_DISPATCH(LIGHTEN, false, false)
1071 }
1072 } // lighten end
1073 else {
1074 if (hasAlpha) {
1075 if (blendAlpha) { PLANARRGB_LD_DISPATCH(DARKEN, true, true) }
1076 else { PLANARRGB_LD_DISPATCH(DARKEN, true, false) }
1077 }
1078 else {
1079 PLANARRGB_LD_DISPATCH(DARKEN, false, false)
1080 }
1081 }
1082 #undef PLANARRGB_LD_DISPATCH
1083 }
1084
1085 // subtract=false only: overlay clip is pre-inverted by Layer::Create when op="Subtract".
1086 template<typename pixel_t,bool chroma, bool has_alpha, bool blend_alpha>
1087 static void layer_planarrgb_add_c(BYTE** dstp8, const BYTE** ovrp8, const BYTE* maskp8, int dst_pitch, int overlay_pitch, int mask_pitch, int width, int height, int opacity_i, int bits_per_pixel) {
1088 pixel_t* dstp_g = reinterpret_cast<pixel_t*>(dstp8[0]);
1089 pixel_t* dstp_b = reinterpret_cast<pixel_t*>(dstp8[1]);
1090 pixel_t* dstp_r = reinterpret_cast<pixel_t*>(dstp8[2]);
1091 // dstp8[3]: written only when blend_alpha=true (both clips have alpha).
1092 pixel_t* dstp_a;
1093 if constexpr (blend_alpha)
1094 dstp_a = reinterpret_cast<pixel_t*>(dstp8[3]);
1095 const pixel_t* ovrp_g = reinterpret_cast<const pixel_t*>(ovrp8[0]);
1096 const pixel_t* ovrp_b = reinterpret_cast<const pixel_t*>(ovrp8[1]);
1097 const pixel_t* ovrp_r = reinterpret_cast<const pixel_t*>(ovrp8[2]);
1098 // maskp: per-pixel blend weight — decoupled from ovrp8[3] to support future mask clip param.
1099 const pixel_t* maskp = reinterpret_cast<const pixel_t*>(maskp8);
1100 // alpha_target: the value blended into dstp_a.
1101 // For plain Add: same as maskp (original overlay A).
1102 // For Subtract: ovrp8[3] is the inverted A; maskp is the saved pre-invert A.
1103 const pixel_t* alpha_target;
1104 if constexpr (blend_alpha)
1105 alpha_target = reinterpret_cast<const pixel_t*>(ovrp8[3]);
1106
1107 dst_pitch /= sizeof(pixel_t);
1108 overlay_pitch /= sizeof(pixel_t);
1109 mask_pitch /= sizeof(pixel_t);
1110
1111 if constexpr (sizeof(pixel_t) == 1)
1112 bits_per_pixel = 8; // make quasi constexpr
1113
1114 // use magic-div
1115 const MagicDiv magic = get_magic_div(bits_per_pixel);
1116 const int max_pixel_value = (1 << bits_per_pixel) - 1;
1117 const int half = max_pixel_value / 2;
1118
1119 for (int y = 0; y < height; ++y) {
1120 for (int x = 0; x < width; ++x) {
1121
1122 uint32_t alpha_eff;
1123 if constexpr (has_alpha) {
1124 const uint32_t alpha_src = (uint32_t)maskp[x];
1125 alpha_eff = (uint32_t)magic_div_rt<pixel_t>(alpha_src * (uint32_t)opacity_i + half, magic);
1126 }
1127 else {
1128 alpha_eff = opacity_i;
1129 }
1130 const uint32_t inv_alpha = max_pixel_value - alpha_eff;
1131
1132 if constexpr (chroma) {
1133 //dstp_r[x] = (pixel_t)(dstp_r[x] + (((ovrp_r[x] - dstp_r[x]) * alpha + rounder) >> bits_per_pixel));
1134 //dstp_g[x] = (pixel_t)(dstp_g[x] + (((ovrp_g[x] - dstp_g[x]) * alpha + rounder) >> bits_per_pixel));
1135 //dstp_b[x] = (pixel_t)(dstp_b[x] + (((ovrp_b[x] - dstp_b[x]) * alpha + rounder) >> bits_per_pixel));
1136 dstp_r[x] = (pixel_t)magic_div_rt<pixel_t>((uint32_t)dstp_r[x] * inv_alpha + (uint32_t)ovrp_r[x] * alpha_eff + half, magic);
1137 dstp_g[x] = (pixel_t)magic_div_rt<pixel_t>((uint32_t)dstp_g[x] * inv_alpha + (uint32_t)ovrp_g[x] * alpha_eff + half, magic);
1138 dstp_b[x] = (pixel_t)magic_div_rt<pixel_t>((uint32_t)dstp_b[x] * inv_alpha + (uint32_t)ovrp_b[x] * alpha_eff + half, magic);
1139 }
1140 else { // use luma instead of overlay
1141 const int luma = (cyb * ovrp_b[x] + cyg * ovrp_g[x] + cyr * ovrp_r[x]) >> 15; // no rounding not really needed here
1142
1143 //dstp_r[x] = (pixel_t)(dstp_r[x] + (((luma - dstp_r[x]) * alpha + rounder) >> bits_per_pixel));
1144 //dstp_g[x] = (pixel_t)(dstp_g[x] + (((luma - dstp_g[x]) * alpha + rounder) >> bits_per_pixel));
1145 //dstp_b[x] = (pixel_t)(dstp_b[x] + (((luma - dstp_b[x]) * alpha + rounder) >> bits_per_pixel));
1146 const uint32_t luma_scaled = (uint32_t)luma * alpha_eff;
1147 dstp_r[x] = (pixel_t)magic_div_rt<pixel_t>((uint32_t)dstp_r[x] * inv_alpha + luma_scaled + half, magic);
1148 dstp_g[x] = (pixel_t)magic_div_rt<pixel_t>((uint32_t)dstp_g[x] * inv_alpha + luma_scaled + half, magic);
1149 dstp_b[x] = (pixel_t)magic_div_rt<pixel_t>((uint32_t)dstp_b[x] * inv_alpha + luma_scaled + half, magic);
1150 }
1151 if constexpr (blend_alpha)
1152 dstp_a[x] = (pixel_t)magic_div_rt<pixel_t>((uint32_t)dstp_a[x] * inv_alpha + (uint32_t)alpha_target[x] * alpha_eff + half, magic);
1153 }
1154 dstp_g += dst_pitch;
1155 dstp_b += dst_pitch;
1156 dstp_r += dst_pitch;
1157 if constexpr (blend_alpha)
1158 dstp_a += dst_pitch;
1159 ovrp_g += overlay_pitch;
1160 ovrp_b += overlay_pitch;
1161 ovrp_r += overlay_pitch;
1162 if constexpr (has_alpha)
1163 maskp += mask_pitch;
1164 if constexpr (blend_alpha)
1165 alpha_target += overlay_pitch;
1166 }
1167 }
1168
1169 // subtract=false only: overlay clip is pre-inverted by Layer::Create when op="Subtract".
1170 template<bool chroma, bool has_alpha, bool blend_alpha>
1171 static void layer_planarrgb_add_f_c(BYTE** dstp8, const BYTE** ovrp8, const BYTE* maskp8, int dst_pitch, int overlay_pitch, int mask_pitch, int width, int height, float opacity) {
1172 float* dstp_g = reinterpret_cast<float*>(dstp8[0]);
1173 float* dstp_b = reinterpret_cast<float*>(dstp8[1]);
1174 float* dstp_r = reinterpret_cast<float*>(dstp8[2]);
1175 // dstp8[3]: written only when blend_alpha=true (both clips have alpha).
1176 float* dstp_a;
1177 if constexpr (blend_alpha)
1178 dstp_a = reinterpret_cast<float*>(dstp8[3]);
1179 const float* ovrp_g = reinterpret_cast<const float*>(ovrp8[0]);
1180 const float* ovrp_b = reinterpret_cast<const float*>(ovrp8[1]);
1181 const float* ovrp_r = reinterpret_cast<const float*>(ovrp8[2]);
1182 // maskp: per-pixel blend weight — decoupled from ovrp8[3].
1183 const float* maskp = reinterpret_cast<const float*>(maskp8);
1184 const float* alpha_target;
1185 if constexpr (blend_alpha)
1186 alpha_target = reinterpret_cast<const float*>(ovrp8[3]);
1187
1188 dst_pitch /= sizeof(float);
1189 overlay_pitch /= sizeof(float);
1190 mask_pitch /= sizeof(float);
1191
1192 for (int y = 0; y < height; ++y) {
1193 for (int x = 0; x < width; ++x) {
1194 float alpha = has_alpha ? maskp[x] * opacity : opacity;
1195
1196 if constexpr (chroma) {
1197 dstp_r[x] = dstp_r[x] + (ovrp_r[x] - dstp_r[x]) * alpha;
1198 dstp_g[x] = dstp_g[x] + (ovrp_g[x] - dstp_g[x]) * alpha;
1199 dstp_b[x] = dstp_b[x] + (ovrp_b[x] - dstp_b[x]) * alpha;
1200 }
1201 else { // use luma instead of overlay
1202 float luma = cyb_f * ovrp_b[x] + cyg_f * ovrp_g[x] + cyr_f * ovrp_r[x];
1203 dstp_r[x] = dstp_r[x] + (luma - dstp_r[x]) * alpha;
1204 dstp_g[x] = dstp_g[x] + (luma - dstp_g[x]) * alpha;
1205 dstp_b[x] = dstp_b[x] + (luma - dstp_b[x]) * alpha;
1206 }
1207 if constexpr (blend_alpha)
1208 dstp_a[x] = dstp_a[x] + (alpha_target[x] - dstp_a[x]) * alpha;
1209 }
1210 dstp_g += dst_pitch;
1211 dstp_b += dst_pitch;
1212 dstp_r += dst_pitch;
1213 if constexpr (blend_alpha)
1214 dstp_a += dst_pitch;
1215 ovrp_g += overlay_pitch;
1216 ovrp_b += overlay_pitch;
1217 ovrp_r += overlay_pitch;
1218 if constexpr (has_alpha)
1219 maskp += mask_pitch;
1220 if constexpr (blend_alpha)
1221 alpha_target += overlay_pitch;
1222 }
1223 }
1224
1225 // ---------------------------------------------------------------------------
1226 // Planar RGB add — SSE4.1 per-plane wrappers (mirrors AVX2 counterparts).
1227 // All planar RGB planes are MASK444. maskp8 is the per-pixel weight.
1228 // chroma=false and float fall back to C templates.
1229
1230 static void layer_planarrgb_add_c_3plane(
1231 BYTE** dstp8, const BYTE** ovrp8, const BYTE* maskp8,
1232 int dst_pitch, int overlay_pitch, int mask_pitch,
1233 int width, int height, int opacity_i, int bits_per_pixel)
1234 {
1235 for (int i = 0; i < 3; i++)
1236 masked_merge_c_impl<MASK444>(
1237 dstp8[i], ovrp8[i], maskp8,
1238 dst_pitch, overlay_pitch, mask_pitch,
1239 width, height, opacity_i, bits_per_pixel);
1240 }
1241
1242 static void layer_planarrgb_add_c_4plane(
1243 BYTE** dstp8, const BYTE** ovrp8, const BYTE* maskp8,
1244 int dst_pitch, int overlay_pitch, int mask_pitch,
1245 int width, int height, int opacity_i, int bits_per_pixel)
1246 {
1247 for (int i = 0; i < 4; i++)
1248 masked_merge_c_impl<MASK444>(
1249 dstp8[i], ovrp8[i], maskp8,
1250 dst_pitch, overlay_pitch, mask_pitch,
1251 width, height, opacity_i, bits_per_pixel);
1252 }
1253
1254
1255 static void get_layer_planarrgb_add_functions(
1256 bool chroma, bool hasAlpha, bool blendAlpha, int bits_per_pixel,
1257 /*out*/layer_planarrgb_add_c_t** layer_fn,
1258 /*out*/layer_planarrgb_add_f_c_t** layer_f_fn)
1259 {
1260
1261 // chroma is true: Layer can use the unified masked and weighted blend routines
1262 // chroma is false: Layer-specific extension
1263 // Integer + hasAlpha + chroma=true: dispatch per-plane to masked_merge_avx2_impl (MASK444).
1264 // chroma=false (blend toward luma) has a different formula — keep C template.
1265 // float: keep C template (float perf is usually fine; could add later).
1266 if (chroma && bits_per_pixel != 32) {
1267 if (hasAlpha) {
1268 *layer_fn = blendAlpha ? layer_planarrgb_add_c_4plane : layer_planarrgb_add_c_3plane;
1269 return;
1270 }
1271 // no alpha: standard weighted merge, to be added later.
1272 }
1273
1274 #define PLANARRGB_ADD_DISPATCH(chroma, has_alpha, blend_alpha) \
1275 { if (bits_per_pixel == 8) \
1276 *layer_fn = layer_planarrgb_add_c<uint8_t, chroma, has_alpha, blend_alpha>; \
1277 else if (bits_per_pixel <= 16) \
1278 *layer_fn = layer_planarrgb_add_c<uint16_t, chroma, has_alpha, blend_alpha>; \
1279 else /* float */ \
1280 *layer_f_fn = layer_planarrgb_add_f_c<chroma, has_alpha, blend_alpha>; \
1281 }
1282
1283 if (hasAlpha) {
1284 if (chroma) {
1285 if (blendAlpha) { PLANARRGB_ADD_DISPATCH(true, true, true) }
1286 else { PLANARRGB_ADD_DISPATCH(true, true, false) }
1287 }
1288 else {
1289 if (blendAlpha) { PLANARRGB_ADD_DISPATCH(false, true, true) }
1290 else { PLANARRGB_ADD_DISPATCH(false, true, false) }
1291 }
1292 }
1293 else {
1294 if (chroma) {
1295 PLANARRGB_ADD_DISPATCH(true, false, false)
1296 }
1297 else {
1298 PLANARRGB_ADD_DISPATCH(false, false, false)
1299 }
1300 }
1301 #undef PLANARRGB_ADD_DISPATCH
1302 }
1303
1304 template<typename pixel_t, bool chroma, bool has_alpha, bool blend_alpha>
1305 1 static void layer_planarrgb_mul_c(BYTE** dstp8, const BYTE** ovrp8, const BYTE* maskp8, int dst_pitch, int overlay_pitch, int mask_pitch, int width, int height, int opacity_i, int bits_per_pixel) {
1306 1 pixel_t* dstp_g = reinterpret_cast<pixel_t*>(dstp8[0]);
1307 1 pixel_t* dstp_b = reinterpret_cast<pixel_t*>(dstp8[1]);
1308 1 pixel_t* dstp_r = reinterpret_cast<pixel_t*>(dstp8[2]);
1309 // dstp8[3]: written only when blend_alpha=true (both clips have alpha).
1310 pixel_t* dstp_a;
1311 if constexpr (blend_alpha)
1312 1 dstp_a = reinterpret_cast<pixel_t*>(dstp8[3]);
1313 1 const pixel_t* ovrp_g = reinterpret_cast<const pixel_t*>(ovrp8[0]);
1314 1 const pixel_t* ovrp_b = reinterpret_cast<const pixel_t*>(ovrp8[1]);
1315 1 const pixel_t* ovrp_r = reinterpret_cast<const pixel_t*>(ovrp8[2]);
1316 // maskp: per-pixel blend weight — decoupled from ovrp8[3].
1317 1 const pixel_t* maskp = reinterpret_cast<const pixel_t*>(maskp8);
1318 // alpha_target: the value multiplied into dstp_a (only when blend_alpha=true).
1319 const pixel_t* alpha_target;
1320 if constexpr (blend_alpha)
1321 1 alpha_target = reinterpret_cast<const pixel_t*>(ovrp8[3]);
1322
1323 1 dst_pitch /= sizeof(pixel_t);
1324 1 overlay_pitch /= sizeof(pixel_t);
1325 1 mask_pitch /= sizeof(pixel_t);
1326
1327 if constexpr (sizeof(pixel_t) == 1)
1328 bits_per_pixel = 8; // make quasi constexpr
1329
1330 // use magic-div
1331 1 const MagicDiv magic = get_magic_div(bits_per_pixel);
1332 1 const int max_pixel_value = (1 << bits_per_pixel) - 1;
1333 1 const int half = max_pixel_value / 2;
1334
1335
2/24
void layer_planarrgb_mul_c<unsigned char, false, false, false>(unsigned char**, unsigned char const**, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 14 → 4 not taken.
✗ Branch 14 → 15 not taken.
void layer_planarrgb_mul_c<unsigned char, false, true, false>(unsigned char**, unsigned char const**, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 16 → 4 not taken.
✗ Branch 16 → 17 not taken.
void layer_planarrgb_mul_c<unsigned char, false, true, true>(unsigned char**, unsigned char const**, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 18 → 4 not taken.
✗ Branch 18 → 19 not taken.
void layer_planarrgb_mul_c<unsigned char, true, false, false>(unsigned char**, unsigned char const**, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 14 → 4 not taken.
✗ Branch 14 → 15 not taken.
void layer_planarrgb_mul_c<unsigned char, true, true, false>(unsigned char**, unsigned char const**, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 16 → 4 not taken.
✗ Branch 16 → 17 not taken.
void layer_planarrgb_mul_c<unsigned char, true, true, true>(unsigned char**, unsigned char const**, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 18 → 4 not taken.
✗ Branch 18 → 19 not taken.
void layer_planarrgb_mul_c<unsigned short, false, false, false>(unsigned char**, unsigned char const**, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 14 → 4 not taken.
✗ Branch 14 → 15 not taken.
void layer_planarrgb_mul_c<unsigned short, false, true, false>(unsigned char**, unsigned char const**, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 16 → 4 not taken.
✗ Branch 16 → 17 not taken.
void layer_planarrgb_mul_c<unsigned short, false, true, true>(unsigned char**, unsigned char const**, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 18 → 4 not taken.
✗ Branch 18 → 19 not taken.
void layer_planarrgb_mul_c<unsigned short, true, false, false>(unsigned char**, unsigned char const**, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 14 → 4 not taken.
✗ Branch 14 → 15 not taken.
void layer_planarrgb_mul_c<unsigned short, true, true, false>(unsigned char**, unsigned char const**, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 16 → 4 not taken.
✗ Branch 16 → 17 not taken.
void layer_planarrgb_mul_c<unsigned short, true, true, true>(unsigned char**, unsigned char const**, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 18 → 4 taken 2 times.
✓ Branch 18 → 19 taken 1 time.
3 for (int y = 0; y < height; ++y) {
1336
2/24
void layer_planarrgb_mul_c<unsigned char, false, false, false>(unsigned char**, unsigned char const**, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 12 → 5 not taken.
✗ Branch 12 → 13 not taken.
void layer_planarrgb_mul_c<unsigned char, false, true, false>(unsigned char**, unsigned char const**, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 14 → 5 not taken.
✗ Branch 14 → 15 not taken.
void layer_planarrgb_mul_c<unsigned char, false, true, true>(unsigned char**, unsigned char const**, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 16 → 5 not taken.
✗ Branch 16 → 17 not taken.
void layer_planarrgb_mul_c<unsigned char, true, false, false>(unsigned char**, unsigned char const**, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 12 → 5 not taken.
✗ Branch 12 → 13 not taken.
void layer_planarrgb_mul_c<unsigned char, true, true, false>(unsigned char**, unsigned char const**, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 14 → 5 not taken.
✗ Branch 14 → 15 not taken.
void layer_planarrgb_mul_c<unsigned char, true, true, true>(unsigned char**, unsigned char const**, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 16 → 5 not taken.
✗ Branch 16 → 17 not taken.
void layer_planarrgb_mul_c<unsigned short, false, false, false>(unsigned char**, unsigned char const**, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 12 → 5 not taken.
✗ Branch 12 → 13 not taken.
void layer_planarrgb_mul_c<unsigned short, false, true, false>(unsigned char**, unsigned char const**, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 14 → 5 not taken.
✗ Branch 14 → 15 not taken.
void layer_planarrgb_mul_c<unsigned short, false, true, true>(unsigned char**, unsigned char const**, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 16 → 5 not taken.
✗ Branch 16 → 17 not taken.
void layer_planarrgb_mul_c<unsigned short, true, false, false>(unsigned char**, unsigned char const**, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 12 → 5 not taken.
✗ Branch 12 → 13 not taken.
void layer_planarrgb_mul_c<unsigned short, true, true, false>(unsigned char**, unsigned char const**, unsigned char const*, int, int, int, int, int, int, int):
✗ Branch 14 → 5 not taken.
✗ Branch 14 → 15 not taken.
void layer_planarrgb_mul_c<unsigned short, true, true, true>(unsigned char**, unsigned char const**, unsigned char const*, int, int, int, int, int, int, int):
✓ Branch 16 → 5 taken 12 times.
✓ Branch 16 → 17 taken 2 times.
14 for (int x = 0; x < width; ++x) {
1337
1338 uint32_t alpha_eff;
1339 if constexpr (has_alpha) {
1340 12 const uint32_t alpha_src = (uint32_t)maskp[x];
1341 12 alpha_eff = (uint32_t)magic_div_rt<pixel_t>(alpha_src * (uint32_t)opacity_i + half, magic);
1342 }
1343 else {
1344 alpha_eff = opacity_i;
1345 }
1346 12 const uint32_t inv_alpha = max_pixel_value - alpha_eff;
1347
1348 if constexpr (chroma) {
1349 // Calculate the multiplied product (A*B)/max
1350 12 const pixel_t prod_r = (pixel_t)(((uint32_t)ovrp_r[x] * (uint32_t)dstp_r[x]) >> bits_per_pixel);
1351 12 const pixel_t prod_g = (pixel_t)(((uint32_t)ovrp_g[x] * (uint32_t)dstp_g[x]) >> bits_per_pixel);
1352 12 const pixel_t prod_b = (pixel_t)(((uint32_t)ovrp_b[x] * (uint32_t)dstp_b[x]) >> bits_per_pixel);
1353
1354 12 dstp_r[x] = (pixel_t)magic_div_rt<pixel_t>((uint32_t)dstp_r[x] * inv_alpha + (uint32_t)prod_r * alpha_eff + half, magic);
1355 12 dstp_g[x] = (pixel_t)magic_div_rt<pixel_t>((uint32_t)dstp_g[x] * inv_alpha + (uint32_t)prod_g * alpha_eff + half, magic);
1356 12 dstp_b[x] = (pixel_t)magic_div_rt<pixel_t>((uint32_t)dstp_b[x] * inv_alpha + (uint32_t)prod_b * alpha_eff + half, magic);
1357 }
1358 else {
1359 // use luma instead of overlay
1360 const int luma = (cyb * ovrp_b[x] + cyg * ovrp_g[x] + cyr * ovrp_r[x]) >> 15;
1361
1362 const pixel_t prod_r = (pixel_t)(((uint32_t)luma * (uint32_t)dstp_r[x]) >> bits_per_pixel);
1363 const pixel_t prod_g = (pixel_t)(((uint32_t)luma * (uint32_t)dstp_g[x]) >> bits_per_pixel);
1364 const pixel_t prod_b = (pixel_t)(((uint32_t)luma * (uint32_t)dstp_b[x]) >> bits_per_pixel);
1365
1366 dstp_r[x] = (pixel_t)magic_div_rt<pixel_t>((uint32_t)dstp_r[x] * inv_alpha + (uint32_t)prod_r * alpha_eff + half, magic);
1367 dstp_g[x] = (pixel_t)magic_div_rt<pixel_t>((uint32_t)dstp_g[x] * inv_alpha + (uint32_t)prod_g * alpha_eff + half, magic);
1368 dstp_b[x] = (pixel_t)magic_div_rt<pixel_t>((uint32_t)dstp_b[x] * inv_alpha + (uint32_t)prod_b * alpha_eff + half, magic);
1369 }
1370
1371 if constexpr (blend_alpha) {
1372 12 const pixel_t prod_a = (pixel_t)(((uint32_t)alpha_target[x] * (uint32_t)dstp_a[x]) >> bits_per_pixel);
1373 24 dstp_a[x] = (pixel_t)magic_div_rt<pixel_t>((uint32_t)dstp_a[x] * inv_alpha + (uint32_t)prod_a * alpha_eff + half, magic);
1374 }
1375 }
1376 2 dstp_g += dst_pitch;
1377 2 dstp_b += dst_pitch;
1378 2 dstp_r += dst_pitch;
1379 if constexpr (blend_alpha)
1380 2 dstp_a += dst_pitch;
1381 2 ovrp_g += overlay_pitch;
1382 2 ovrp_b += overlay_pitch;
1383 2 ovrp_r += overlay_pitch;
1384 if constexpr (has_alpha)
1385 2 maskp += mask_pitch;
1386 if constexpr (blend_alpha)
1387 2 alpha_target += overlay_pitch;
1388 }
1389 1 }
1390
1391 template<bool chroma, bool has_alpha, bool blend_alpha>
1392 static void layer_planarrgb_mul_f_c(BYTE** dstp8, const BYTE** ovrp8, const BYTE* maskp8, int dst_pitch, int overlay_pitch, int mask_pitch, int width, int height, float opacity) {
1393 float* dstp_g = reinterpret_cast<float*>(dstp8[0]);
1394 float* dstp_b = reinterpret_cast<float*>(dstp8[1]);
1395 float* dstp_r = reinterpret_cast<float*>(dstp8[2]);
1396 // dstp8[3]: written only when blend_alpha=true (both clips have alpha).
1397 float* dstp_a;
1398 if constexpr (blend_alpha)
1399 dstp_a = reinterpret_cast<float*>(dstp8[3]);
1400 const float* ovrp_g = reinterpret_cast<const float*>(ovrp8[0]);
1401 const float* ovrp_b = reinterpret_cast<const float*>(ovrp8[1]);
1402 const float* ovrp_r = reinterpret_cast<const float*>(ovrp8[2]);
1403 // maskp: per-pixel blend weight — decoupled from ovrp8[3].
1404 const float* maskp = reinterpret_cast<const float*>(maskp8);
1405 const float* alpha_target;
1406 if constexpr (blend_alpha)
1407 alpha_target = reinterpret_cast<const float*>(ovrp8[3]);
1408
1409 dst_pitch /= sizeof(float);
1410 overlay_pitch /= sizeof(float);
1411 mask_pitch /= sizeof(float);
1412
1413 for (int y = 0; y < height; ++y) {
1414 for (int x = 0; x < width; ++x) {
1415 float alpha = has_alpha ? maskp[x] * opacity : opacity;
1416
1417 if constexpr (chroma) {
1418 dstp_r[x] = dstp_r[x] + (ovrp_r[x] * dstp_r[x] - dstp_r[x]) * alpha;
1419 dstp_g[x] = dstp_g[x] + (ovrp_g[x] * dstp_g[x] - dstp_g[x]) * alpha;
1420 dstp_b[x] = dstp_b[x] + (ovrp_b[x] * dstp_b[x] - dstp_b[x]) * alpha;
1421 }
1422 else { // use luma instead of overlay
1423 float luma = cyb_f * ovrp_b[x] + cyg_f * ovrp_g[x] + cyr_f * ovrp_r[x];
1424 dstp_r[x] = dstp_r[x] + (luma * dstp_r[x] - dstp_r[x]) * alpha;
1425 dstp_g[x] = dstp_g[x] + (luma * dstp_g[x] - dstp_g[x]) * alpha;
1426 dstp_b[x] = dstp_b[x] + (luma * dstp_b[x] - dstp_b[x]) * alpha;
1427 }
1428 if constexpr (blend_alpha)
1429 dstp_a[x] = dstp_a[x] + (alpha_target[x] * dstp_a[x] - dstp_a[x]) * alpha;
1430 }
1431 dstp_g += dst_pitch;
1432 dstp_b += dst_pitch;
1433 dstp_r += dst_pitch;
1434 if constexpr (blend_alpha)
1435 dstp_a += dst_pitch;
1436 ovrp_g += overlay_pitch;
1437 ovrp_b += overlay_pitch;
1438 ovrp_r += overlay_pitch;
1439 if constexpr (has_alpha)
1440 maskp += mask_pitch;
1441 if constexpr (blend_alpha)
1442 alpha_target += overlay_pitch;
1443 }
1444 }
1445
1446 1 static void get_layer_planarrgb_mul_functions(
1447 bool chroma, bool hasAlpha, bool blendAlpha, int bits_per_pixel,
1448 /*out*/layer_planarrgb_mul_c_t** layer_fn,
1449 /*out*/layer_planarrgb_mul_f_c_t** layer_f_fn)
1450 {
1451 #define PLANARRGB_MUL_DISPATCH(chroma, has_alpha, blend_alpha) \
1452 { if (bits_per_pixel == 8) \
1453 *layer_fn = layer_planarrgb_mul_c<uint8_t, chroma, has_alpha, blend_alpha>; \
1454 else if (bits_per_pixel <= 16) \
1455 *layer_fn = layer_planarrgb_mul_c<uint16_t, chroma, has_alpha, blend_alpha>; \
1456 else /* float */ \
1457 *layer_f_fn = layer_planarrgb_mul_f_c<chroma, has_alpha, blend_alpha>; \
1458 }
1459
1460
1/2
✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 26 not taken.
1 if (hasAlpha) {
1461
1/2
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 15 not taken.
1 if (chroma) {
1462
3/6
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 10 not taken.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 1 time.
✓ Branch 7 → 8 taken 1 time.
✗ Branch 7 → 9 not taken.
1 if (blendAlpha) { PLANARRGB_MUL_DISPATCH(true, true, true) }
1463 else { PLANARRGB_MUL_DISPATCH(true, true, false) }
1464 }
1465 else {
1466 if (blendAlpha) { PLANARRGB_MUL_DISPATCH(false, true, true) }
1467 else { PLANARRGB_MUL_DISPATCH(false, true, false) }
1468 }
1469 }
1470 else {
1471 if (chroma) {
1472 PLANARRGB_MUL_DISPATCH(true, false, false)
1473 }
1474 else {
1475 PLANARRGB_MUL_DISPATCH(false, false, false)
1476 }
1477 }
1478 #undef PLANARRGB_MUL_DISPATCH
1479 1 }
1480
1481 // ---------------------------------------------------------------------------
1482 // Packed RGBA (RGB32 / RGB64) blend dispatcher — C reference.
1483 // Returns the appropriate masked_blend_packedrgba_c instantiation for the
1484 // given bit depth. Subtract is handled by pre-inverting the overlay and
1485 // passing a separate maskp8 pointer in the caller (Layer::Create/GetFrame).
1486 // The C reference function selects the alpha source at runtime via the
1487 // maskp8 null-check, so a single function covers both Add and Subtract.
1488 // ---------------------------------------------------------------------------
1489 1 static void get_layer_packedrgb_blend_functions(
1490 bool has_separate_mask,
1491 int bits_per_pixel,
1492 layer_packedrgb_blend_c_t** fn)
1493 {
1494
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 7 taken 1 time.
1 if (bits_per_pixel == 8)
1495 *fn = has_separate_mask ? masked_blend_packedrgba_c<uint8_t, true> : masked_blend_packedrgba_c<uint8_t, false>;
1496 else // 16-bit (RGB64)
1497
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 1 time.
1 *fn = has_separate_mask ? masked_blend_packedrgba_c<uint16_t, true> : masked_blend_packedrgba_c<uint16_t, false>;
1498 1 }
1499
1500 // Clean up rowprep macros (defined near top of this file or by including TU).
1501 #undef LAYER_ROWPREP_FN
1502
1503