filters/overlay/OF_blend.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // Avisynth v2.5. Copyright 2002 Ben Rudiak-Gould et al. | ||
| 2 | // http://avisynth.nl | ||
| 3 | |||
| 4 | // This program is free software; you can redistribute it and/or modify | ||
| 5 | // it under the terms of the GNU General Public License as published by | ||
| 6 | // the Free Software Foundation; either version 2 of the License, or | ||
| 7 | // (at your option) any later version. | ||
| 8 | // | ||
| 9 | // This program is distributed in the hope that it will be useful, | ||
| 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | // GNU General Public License for more details. | ||
| 13 | // | ||
| 14 | // You should have received a copy of the GNU General Public License | ||
| 15 | // along with this program; if not, write to the Free Software | ||
| 16 | // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit | ||
| 17 | // http://www.gnu.org/copyleft/gpl.html . | ||
| 18 | // | ||
| 19 | // Linking Avisynth statically or dynamically with other modules is making a | ||
| 20 | // combined work based on Avisynth. Thus, the terms and conditions of the GNU | ||
| 21 | // General Public License cover the whole combination. | ||
| 22 | // | ||
| 23 | // As a special exception, the copyright holders of Avisynth give you | ||
| 24 | // permission to link Avisynth with independent modules that communicate with | ||
| 25 | // Avisynth solely through the interfaces defined in avisynth.h, regardless of the license | ||
| 26 | // terms of these independent modules, and to copy and distribute the | ||
| 27 | // resulting combined work under terms of your choice, provided that | ||
| 28 | // every copy of the combined work is accompanied by a complete copy of | ||
| 29 | // the source code of Avisynth (the version of Avisynth used to produce the | ||
| 30 | // combined work), being distributed under the terms of the GNU General | ||
| 31 | // Public License plus this exception. An independent module is a module | ||
| 32 | // which is not derived from or based on Avisynth, such as 3rd-party filters, | ||
| 33 | // import and export plugins, or graphical user interfaces. | ||
| 34 | |||
| 35 | // Overlay (c) 2003, 2004 by Klaus Post | ||
| 36 | |||
| 37 | #include "overlayfunctions.h" | ||
| 38 | #include "blend_common.h" | ||
| 39 | #ifdef INTEL_INTRINSICS | ||
| 40 | #include "intel/blend_common_sse.h" | ||
| 41 | #include "intel/blend_common_avx2.h" | ||
| 42 | #endif | ||
| 43 | #ifdef NEON_INTRINSICS | ||
| 44 | #include "aarch64/blend_common_neon.h" | ||
| 45 | #endif | ||
| 46 | |||
| 47 | |||
| 48 | #include <stdint.h> | ||
| 49 | #include <type_traits> | ||
| 50 | |||
| 51 | // --------------------------------------------------------------------------- | ||
| 52 | // Getters: select the best masked_merge_fn_t* / masked_merge_float_fn_t* | ||
| 53 | // for the current CPU and plane type (luma vs chroma). | ||
| 54 | // --------------------------------------------------------------------------- | ||
| 55 | |||
| 56 | // Float masked blend — placement-aware, parallel structure to the integer getter. | ||
| 57 | // is_lumamask_based_chroma=false → always MASK444 (luma). is_lumamask_based_chroma=true → placement-aware. | ||
| 58 | // Note that when we use an exactly calculated and sized chroma mask, which is actually | ||
| 59 | // in 1:1 relation with the chroma plane, then is_lumamask_based_chroma=false must be given here. | ||
| 60 | ✗ | static masked_merge_float_fn_t* get_overlay_blend_masked_float_fn( | |
| 61 | int cpuFlags, bool is_lumamask_based_chroma, int placement, const VideoInfo& vi_internal) | ||
| 62 | { | ||
| 63 | ✗ | MaskMode maskMode = MASK444; | |
| 64 | ✗ | if (is_lumamask_based_chroma) { | |
| 65 | ✗ | if (vi_internal.IsYV411()) | |
| 66 | ✗ | maskMode = MASK411; | |
| 67 | ✗ | else if (vi_internal.Is420()) | |
| 68 | ✗ | maskMode = (placement == PLACEMENT_MPEG1) ? MASK420 : (placement == PLACEMENT_TOPLEFT) ? MASK420_TOPLEFT : MASK420_MPEG2; | |
| 69 | ✗ | else if (vi_internal.Is422()) | |
| 70 | ✗ | maskMode = (placement == PLACEMENT_MPEG1) ? MASK422 : (placement == PLACEMENT_TOPLEFT) ? MASK422_TOPLEFT : MASK422_MPEG2; | |
| 71 | } | ||
| 72 | |||
| 73 | #ifdef INTEL_INTRINSICS | ||
| 74 | ✗ | if (cpuFlags & CPUF_AVX2) return get_overlay_blend_masked_float_fn_avx2(is_lumamask_based_chroma, maskMode); | |
| 75 | ✗ | if (cpuFlags & CPUF_SSE4_1) return get_overlay_blend_masked_float_fn_sse41(is_lumamask_based_chroma, maskMode); | |
| 76 | ✗ | if ((cpuFlags & CPUF_SSE2) && maskMode == MASK444) return &masked_merge_float_sse2; | |
| 77 | #endif | ||
| 78 | #ifdef NEON_INTRINSICS | ||
| 79 | if (cpuFlags & CPUF_ARM_NEON) return get_overlay_blend_masked_float_fn_neon(is_lumamask_based_chroma, maskMode); | ||
| 80 | #endif | ||
| 81 | ✗ | return get_overlay_blend_masked_float_fn_c(is_lumamask_based_chroma, maskMode); | |
| 82 | } | ||
| 83 | |||
| 84 | // Integer masked blend: compute MaskMode from the internal VI + placement, | ||
| 85 | // then dispatch to the appropriate SIMD getter. | ||
| 86 | // is_lumamask_based_chroma=false → always MASK444 (luma plane is never sub-sampled). | ||
| 87 | // Note that when we use an exactly calculated and sized chroma mask, which is actually | ||
| 88 | // in 1:1 relation with the chroma plane, then is_lumamask_based_chroma=false must be given here. | ||
| 89 | 9 | static masked_merge_fn_t* get_overlay_blend_masked_fn( | |
| 90 | int cpuFlags, bool is_lumamask_based_chroma, int placement, const VideoInfo& vi_internal) | ||
| 91 | { | ||
| 92 | 9 | MaskMode maskMode = MASK444; | |
| 93 |
2/2✓ Branch 2 → 3 taken 3 times.
✓ Branch 2 → 20 taken 6 times.
|
9 | if (is_lumamask_based_chroma) { |
| 94 |
1/2✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 3 times.
|
3 | if (vi_internal.IsYV411()) |
| 95 | ✗ | maskMode = MASK411; | |
| 96 |
1/2✗ Branch 7 → 8 not taken.
✓ Branch 7 → 13 taken 3 times.
|
3 | else if (vi_internal.Is420()) |
| 97 | ✗ | maskMode = (placement == PLACEMENT_MPEG1) ? MASK420 : (placement == PLACEMENT_TOPLEFT) ? MASK420_TOPLEFT : MASK420_MPEG2; | |
| 98 |
1/2✗ Branch 14 → 15 not taken.
✓ Branch 14 → 20 taken 3 times.
|
3 | else if (vi_internal.Is422()) |
| 99 | ✗ | maskMode = (placement == PLACEMENT_MPEG1) ? MASK422 : (placement == PLACEMENT_TOPLEFT) ? MASK422_TOPLEFT : MASK422_MPEG2; | |
| 100 | } | ||
| 101 | |||
| 102 | #ifdef INTEL_INTRINSICS | ||
| 103 |
1/2✓ Branch 20 → 21 taken 9 times.
✗ Branch 20 → 23 not taken.
|
9 | if (cpuFlags & CPUF_AVX2) return get_overlay_blend_masked_fn_avx2(is_lumamask_based_chroma, maskMode); |
| 104 | ✗ | if (cpuFlags & CPUF_SSE4_1) return get_overlay_blend_masked_fn_sse41(is_lumamask_based_chroma, maskMode); | |
| 105 | #endif | ||
| 106 | #ifdef NEON_INTRINSICS | ||
| 107 | if (cpuFlags & CPUF_ARM_NEON) return get_overlay_blend_masked_fn_neon(is_lumamask_based_chroma, maskMode); | ||
| 108 | #endif | ||
| 109 | ✗ | return get_overlay_blend_masked_fn_c(is_lumamask_based_chroma, maskMode); | |
| 110 | } | ||
| 111 | |||
| 112 | // Wrappers: adapt overlay_blend_plane_masked_opacity_t to weighted_merge SIMD functions. | ||
| 113 | // weight = round(opacity_f * 32768); invweight = 32768 - weight. mask ptr is ignored. | ||
| 114 | #ifdef NEON_INTRINSICS | ||
| 115 | static void overlay_blend_neon_weighted_wrap( | ||
| 116 | BYTE* p1, const BYTE* p2, const BYTE* /*mask*/, | ||
| 117 | const int p1_pitch, const int p2_pitch, const int /*mask_pitch*/, | ||
| 118 | const int width, const int height, const float opacity_f, | ||
| 119 | const int bits_per_pixel) | ||
| 120 | { | ||
| 121 | const int weight = static_cast<int>(opacity_f * 32768 + 0.5f); | ||
| 122 | if (weight == 0 || weight == 32768) { | ||
| 123 | // Avoid calling the full weighted_merge when one of the weights is zero, in case of no early out | ||
| 124 | weighted_merge_return_a_or_b(p1, p2, p1_pitch, p2_pitch, width, height, weight, 32768 - weight, bits_per_pixel); | ||
| 125 | return; | ||
| 126 | } | ||
| 127 | weighted_merge_neon(p1, p2, p1_pitch, p2_pitch, width, height, weight, 32768 - weight, bits_per_pixel); | ||
| 128 | } | ||
| 129 | |||
| 130 | static void overlay_blend_neon_weighted_float_wrap( | ||
| 131 | BYTE* p1, const BYTE* p2, const BYTE* /*mask*/, | ||
| 132 | const int p1_pitch, const int p2_pitch, const int /*mask_pitch*/, | ||
| 133 | const int width, const int height, const float opacity_f, | ||
| 134 | const int /*bits_per_pixel*/) | ||
| 135 | { | ||
| 136 | weighted_merge_float_neon(p1, p2, p1_pitch, p2_pitch, width, height, opacity_f); | ||
| 137 | } | ||
| 138 | #endif // NEON_INTRINSICS | ||
| 139 | |||
| 140 | #ifdef INTEL_INTRINSICS | ||
| 141 | 18 | static void overlay_blend_weighted_avx2( | |
| 142 | BYTE* p1, const BYTE* p2, const BYTE* /*mask*/, | ||
| 143 | const int p1_pitch, const int p2_pitch, const int /*mask_pitch*/, | ||
| 144 | const int width, const int height, const float opacity_f, | ||
| 145 | const int bits_per_pixel) | ||
| 146 | { | ||
| 147 | 18 | const int weight = static_cast<int>(opacity_f * 32768 + 0.5f); | |
| 148 |
2/4✓ Branch 2 → 3 taken 18 times.
✗ Branch 2 → 4 not taken.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 6 taken 18 times.
|
18 | if (weight == 0 || weight == 32768) { |
| 149 | // Avoid calling the full weighted_merge when one of the weights is zero, in case of no early out | ||
| 150 | ✗ | weighted_merge_return_a_or_b(p1, p2, p1_pitch, p2_pitch, width, height, weight, 32768 - weight, bits_per_pixel); | |
| 151 | ✗ | return; | |
| 152 | } | ||
| 153 | 18 | weighted_merge_avx2(p1, p2, p1_pitch, p2_pitch, width, height, weight, 32768 - weight, bits_per_pixel); | |
| 154 | } | ||
| 155 | |||
| 156 | ✗ | static void overlay_blend_weighted_sse2( | |
| 157 | BYTE* p1, const BYTE* p2, const BYTE* /*mask*/, | ||
| 158 | const int p1_pitch, const int p2_pitch, const int /*mask_pitch*/, | ||
| 159 | const int width, const int height, const float opacity_f, | ||
| 160 | const int bits_per_pixel) | ||
| 161 | { | ||
| 162 | ✗ | const int weight = static_cast<int>(opacity_f * 32768 + 0.5f); | |
| 163 | ✗ | if (weight == 0 || weight == 32768) { | |
| 164 | // Avoid calling the full weighted_merge when one of the weights is zero, in case of no early out | ||
| 165 | ✗ | weighted_merge_return_a_or_b(p1, p2, p1_pitch, p2_pitch, width, height, weight, 32768 - weight, bits_per_pixel); | |
| 166 | ✗ | return; | |
| 167 | } | ||
| 168 | ✗ | weighted_merge_sse2(p1, p2, p1_pitch, p2_pitch, width, height, weight, 32768 - weight, bits_per_pixel); | |
| 169 | } | ||
| 170 | |||
| 171 | ✗ | static void overlay_blend_weighted_float_avx2( | |
| 172 | BYTE* p1, const BYTE* p2, const BYTE* /*mask*/, | ||
| 173 | const int p1_pitch, const int p2_pitch, const int /*mask_pitch*/, | ||
| 174 | const int width, const int height, const float opacity_f, | ||
| 175 | const int /*bits_per_pixel*/) | ||
| 176 | { | ||
| 177 | ✗ | weighted_merge_float_avx2(p1, p2, p1_pitch, p2_pitch, width, height, opacity_f); | |
| 178 | ✗ | } | |
| 179 | |||
| 180 | ✗ | static void overlay_blend_weighted_float_sse2( | |
| 181 | BYTE* p1, const BYTE* p2, const BYTE* /*mask*/, | ||
| 182 | const int p1_pitch, const int p2_pitch, const int /*mask_pitch*/, | ||
| 183 | const int width, const int height, const float opacity_f, | ||
| 184 | const int /*bits_per_pixel*/) | ||
| 185 | { | ||
| 186 | ✗ | weighted_merge_float_sse2(p1, p2, p1_pitch, p2_pitch, width, height, opacity_f); | |
| 187 | ✗ | } | |
| 188 | #endif | ||
| 189 | |||
| 190 | // Wrapper: adapt overlay_blend_plane_masked_opacity_t to weighted_merge_c. | ||
| 191 | // weight = round(opacity_f * 32768); invweight = 32768 - weight. | ||
| 192 | ✗ | static void overlay_blend_weighted_c( | |
| 193 | BYTE* p1, const BYTE* p2, const BYTE* /*mask*/, | ||
| 194 | const int p1_pitch, const int p2_pitch, const int /*mask_pitch*/, | ||
| 195 | const int width, const int height, const float opacity_f, | ||
| 196 | const int bits_per_pixel) | ||
| 197 | { | ||
| 198 | ✗ | const int weight = static_cast<int>(opacity_f * 32768 + 0.5f); | |
| 199 | ✗ | if (weight == 0 || weight == 32768) { | |
| 200 | // Avoid calling the full weighted_merge_c when one of the weights is zero, in case of no early out | ||
| 201 | ✗ | weighted_merge_return_a_or_b(p1, p2, p1_pitch, p2_pitch, width, height, weight, 32768 - weight, bits_per_pixel); | |
| 202 | ✗ | return; | |
| 203 | } | ||
| 204 | ✗ | weighted_merge_c(p1, p2, p1_pitch, p2_pitch, width, height, weight, 32768 - weight, bits_per_pixel); | |
| 205 | } | ||
| 206 | |||
| 207 | ✗ | static void overlay_blend_weighted_float_c( | |
| 208 | BYTE* p1, const BYTE* p2, const BYTE* /*mask*/, | ||
| 209 | const int p1_pitch, const int p2_pitch, const int /*mask_pitch*/, | ||
| 210 | const int width, const int height, const float opacity_f, | ||
| 211 | const int /*bits_per_pixel*/) | ||
| 212 | { | ||
| 213 | ✗ | weighted_merge_float_c(p1, p2, p1_pitch, p2_pitch, width, height, opacity_f); | |
| 214 | ✗ | } | |
| 215 | |||
| 216 | // --------------------------------------------------------------------------- | ||
| 217 | // Per-row chroma scratch helpers — runtime-dispatch on MaskMode to call the | ||
| 218 | // compile-time prepare_effective_mask_for_row. | ||
| 219 | // The caller pre-sizes `buf` to chroma_w; mask_pitch is in elements, not bytes. | ||
| 220 | // --------------------------------------------------------------------------- | ||
| 221 | template<typename pixel_t, bool full_opacity = true> | ||
| 222 | ✗ | static void do_fill_chroma_row( | |
| 223 | std::vector<pixel_t>& buf, const pixel_t* luma_row, | ||
| 224 | int luma_pitch_pixels, int chroma_w, MaskMode mode, | ||
| 225 | int opacity_i = 0, int half = 0, MagicDiv magic = {}) | ||
| 226 | { | ||
| 227 | ✗ | switch (mode) { | |
| 228 | ✗ | case MASK411: | |
| 229 | ✗ | prepare_effective_mask_for_row<MASK411, pixel_t, full_opacity>(luma_row, luma_pitch_pixels, chroma_w, buf, opacity_i, half, magic); break; | |
| 230 | ✗ | case MASK420: | |
| 231 | ✗ | prepare_effective_mask_for_row<MASK420, pixel_t, full_opacity>(luma_row, luma_pitch_pixels, chroma_w, buf, opacity_i, half, magic); break; | |
| 232 | ✗ | case MASK420_MPEG2: | |
| 233 | ✗ | prepare_effective_mask_for_row<MASK420_MPEG2, pixel_t, full_opacity>(luma_row, luma_pitch_pixels, chroma_w, buf, opacity_i, half, magic); break; | |
| 234 | ✗ | case MASK420_TOPLEFT: | |
| 235 | ✗ | prepare_effective_mask_for_row<MASK420_TOPLEFT, pixel_t, full_opacity>(luma_row, luma_pitch_pixels, chroma_w, buf, opacity_i, half, magic); break; | |
| 236 | ✗ | case MASK422: | |
| 237 | ✗ | prepare_effective_mask_for_row<MASK422, pixel_t, full_opacity>(luma_row, luma_pitch_pixels, chroma_w, buf, opacity_i, half, magic); break; | |
| 238 | ✗ | case MASK422_MPEG2: | |
| 239 | ✗ | prepare_effective_mask_for_row<MASK422_MPEG2, pixel_t, full_opacity>(luma_row, luma_pitch_pixels, chroma_w, buf, opacity_i, half, magic); break; | |
| 240 | ✗ | case MASK422_TOPLEFT: | |
| 241 | ✗ | prepare_effective_mask_for_row<MASK422_TOPLEFT, pixel_t, full_opacity>(luma_row, luma_pitch_pixels, chroma_w, buf, opacity_i, half, magic); break; | |
| 242 | ✗ | default: break; | |
| 243 | } | ||
| 244 | ✗ | } | |
| 245 | |||
| 246 | template<bool full_opacity = true> | ||
| 247 | ✗ | static void do_fill_chroma_row_f( | |
| 248 | std::vector<float>& buf, const float* luma_row, | ||
| 249 | int luma_pitch_floats, int chroma_w, MaskMode mode, | ||
| 250 | float opacity_f = 1.0f) | ||
| 251 | { | ||
| 252 | ✗ | switch (mode) { | |
| 253 | ✗ | case MASK411: | |
| 254 | ✗ | prepare_effective_mask_for_row_float_c<MASK411, full_opacity>(luma_row, luma_pitch_floats, chroma_w, buf, opacity_f); break; | |
| 255 | ✗ | case MASK420: | |
| 256 | ✗ | prepare_effective_mask_for_row_float_c<MASK420, full_opacity>(luma_row, luma_pitch_floats, chroma_w, buf, opacity_f); break; | |
| 257 | ✗ | case MASK420_MPEG2: | |
| 258 | ✗ | prepare_effective_mask_for_row_float_c<MASK420_MPEG2, full_opacity>(luma_row, luma_pitch_floats, chroma_w, buf, opacity_f); break; | |
| 259 | ✗ | case MASK420_TOPLEFT: | |
| 260 | ✗ | prepare_effective_mask_for_row_float_c<MASK420_TOPLEFT, full_opacity>(luma_row, luma_pitch_floats, chroma_w, buf, opacity_f); break; | |
| 261 | ✗ | case MASK422: | |
| 262 | ✗ | prepare_effective_mask_for_row_float_c<MASK422, full_opacity>(luma_row, luma_pitch_floats, chroma_w, buf, opacity_f); break; | |
| 263 | ✗ | case MASK422_MPEG2: | |
| 264 | ✗ | prepare_effective_mask_for_row_float_c<MASK422_MPEG2, full_opacity>(luma_row, luma_pitch_floats, chroma_w, buf, opacity_f); break; | |
| 265 | ✗ | case MASK422_TOPLEFT: | |
| 266 | ✗ | prepare_effective_mask_for_row_float_c<MASK422_TOPLEFT, full_opacity>(luma_row, luma_pitch_floats, chroma_w, buf, opacity_f); break; | |
| 267 | ✗ | default: break; | |
| 268 | } | ||
| 269 | ✗ | } | |
| 270 | |||
| 271 | // do_fill_chroma_row_sse41 and do_fill_chroma_row_avx2 are declared in | ||
| 272 | // intel/blend_common_sse.h and intel/blend_common_avx2.h respectively, | ||
| 273 | // and defined (with explicit instantiations) in their matching .cpp files. | ||
| 274 | |||
| 275 | 6 | void OL_BlendImage::DoBlendImageMask(ImageOverlayInternal* base, ImageOverlayInternal* overlay, ImageOverlayInternal* mask) { | |
| 276 |
1/2✓ Branch 2 → 3 taken 6 times.
✗ Branch 2 → 4 not taken.
|
6 | if (bits_per_pixel == 8) |
| 277 | 6 | BlendImageMask<uint8_t>(base, overlay, mask); | |
| 278 | ✗ | else if (bits_per_pixel <= 16) | |
| 279 | ✗ | BlendImageMask<uint16_t>(base, overlay, mask); | |
| 280 | ✗ | else if (bits_per_pixel == 32) | |
| 281 | ✗ | BlendImageMask<float>(base, overlay, mask); | |
| 282 | 6 | } | |
| 283 | |||
| 284 | 7 | void OL_BlendImage::DoBlendImage(ImageOverlayInternal* base, ImageOverlayInternal* overlay) { | |
| 285 |
1/2✓ Branch 2 → 3 taken 7 times.
✗ Branch 2 → 4 not taken.
|
7 | if (bits_per_pixel == 8) |
| 286 | 7 | BlendImage<uint8_t>(base, overlay); | |
| 287 | ✗ | else if (bits_per_pixel <= 16) | |
| 288 | ✗ | BlendImage<uint16_t>(base, overlay); | |
| 289 | ✗ | else if (bits_per_pixel == 32) | |
| 290 | ✗ | BlendImage<float>(base, overlay); | |
| 291 | 7 | } | |
| 292 | |||
| 293 | |||
| 294 | template<typename pixel_t> | ||
| 295 | 6 | void OL_BlendImage::BlendImageMask(ImageOverlayInternal* base, ImageOverlayInternal* overlay, ImageOverlayInternal* mask) { | |
| 296 | 6 | int w = base->w(); | |
| 297 | 6 | int h = base->h(); | |
| 298 | |||
| 299 | 6 | int planeindex_from = 0; | |
| 300 | 6 | int planeindex_to = 0; | |
| 301 | |||
| 302 |
1/6void OL_BlendImage::BlendImageMask<float>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 8 not taken.
void OL_BlendImage::BlendImageMask<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 4 → 5 taken 6 times.
✗ Branch 4 → 8 not taken.
void OL_BlendImage::BlendImageMask<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 8 not taken.
|
6 | if (of_mode == OF_Blend) { |
| 303 | 6 | planeindex_from = 0; | |
| 304 |
1/6void OL_BlendImage::BlendImageMask<float>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 7 not taken.
void OL_BlendImage::BlendImageMask<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 6 times.
void OL_BlendImage::BlendImageMask<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 7 not taken.
|
6 | planeindex_to = greyscale ? 0 : 2; |
| 305 | } | ||
| 306 | ✗ | else if (of_mode == OF_Luma) { | |
| 307 | ✗ | planeindex_from = 0; | |
| 308 | ✗ | planeindex_to = 0; | |
| 309 | } | ||
| 310 | ✗ | else if (of_mode == OF_Chroma) { | |
| 311 | ✗ | if (greyscale) | |
| 312 | ✗ | return; | |
| 313 | ✗ | planeindex_from = 1; | |
| 314 | ✗ | planeindex_to = 2; | |
| 315 | } | ||
| 316 | |||
| 317 | 6 | const int cpuFlags = env->GetCPUFlags(); | |
| 318 | |||
| 319 | // For RGB all planes are full-resolution (no subsampling), so G/B planes use the luma path. | ||
| 320 | // For YUV, planes 1/2 are chroma and use the placement-aware path. | ||
| 321 | 6 | const bool use_chroma_fn = !rgb; | |
| 322 | |||
| 323 | // Per-row scratch path: imghelpers stores the luma mask pointer in planes 1/2 for | ||
| 324 | // subsampled greymask; BlendImageMask fills a per-row scratch buffer from luma rows, | ||
| 325 | // shared for both U and V. | ||
| 326 | // Active when use444=false keeps vi_internal at 420/422/411 AND greymask=true. | ||
| 327 | // Not active when use444=true or input is natively 444/RGB: vi_internal is then at full | ||
| 328 | // chroma resolution, Is420/Is422/IsYV411 == false, so is_subsampled = false. | ||
| 329 |
5/18void OL_BlendImage::BlendImageMask<float>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 16 → 17 not taken.
✗ Branch 16 → 21 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 18 → 21 not taken.
✗ Branch 20 → 21 not taken.
✗ Branch 20 → 22 not taken.
void OL_BlendImage::BlendImageMask<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 16 → 17 taken 4 times.
✓ Branch 16 → 21 taken 2 times.
✓ Branch 18 → 19 taken 3 times.
✓ Branch 18 → 21 taken 1 time.
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 22 taken 3 times.
void OL_BlendImage::BlendImageMask<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 16 → 17 not taken.
✗ Branch 16 → 21 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 18 → 21 not taken.
✗ Branch 20 → 21 not taken.
✗ Branch 20 → 22 not taken.
|
6 | const bool is_subsampled = vi_internal.Is420() || vi_internal.Is422() || vi_internal.IsYV411(); |
| 330 |
4/18void OL_BlendImage::BlendImageMask<float>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 23 → 24 not taken.
✗ Branch 23 → 27 not taken.
✗ Branch 24 → 25 not taken.
✗ Branch 24 → 27 not taken.
✗ Branch 25 → 26 not taken.
✗ Branch 25 → 27 not taken.
void OL_BlendImage::BlendImageMask<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 23 → 24 taken 6 times.
✗ Branch 23 → 27 not taken.
✓ Branch 24 → 25 taken 6 times.
✗ Branch 24 → 27 not taken.
✓ Branch 25 → 26 taken 3 times.
✓ Branch 25 → 27 taken 3 times.
void OL_BlendImage::BlendImageMask<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 23 → 24 not taken.
✗ Branch 23 → 27 not taken.
✗ Branch 24 → 25 not taken.
✗ Branch 24 → 27 not taken.
✗ Branch 25 → 26 not taken.
✗ Branch 25 → 27 not taken.
|
6 | const bool use_scratch_path = greymask_mask && use_chroma_fn && is_subsampled; |
| 331 | |||
| 332 | if constexpr (std::is_same_v<pixel_t, float>) { | ||
| 333 | // Float path: separate luma/chroma function pointers. | ||
| 334 | // blend_fn_chroma uses is_lumamask_based_chroma=false (→ MASK444) in the normal path | ||
| 335 | // because the mask plane is already at chroma resolution (greymask=false or non-subsampled). | ||
| 336 | // The scratch path pre-fills chroma-resolution scratch and calls blend_fn_luma on it. | ||
| 337 | ✗ | masked_merge_float_fn_t* blend_fn_luma = get_overlay_blend_masked_float_fn(cpuFlags, false, placement, vi_internal); | |
| 338 | ✗ | masked_merge_float_fn_t* blend_fn_chroma = | |
| 339 | ✗ | use_scratch_path ? blend_fn_luma | |
| 340 | ✗ | : get_overlay_blend_masked_float_fn(cpuFlags, true, placement, vi_internal); | |
| 341 | |||
| 342 | ✗ | if (use_scratch_path) { | |
| 343 | // Luma plane (if applicable) | ||
| 344 | ✗ | if (planeindex_from == 0) { | |
| 345 | ✗ | blend_fn_luma( | |
| 346 | ✗ | base->GetPtrByIndex(0), overlay->GetPtrByIndex(0), mask->GetPtrByIndex(0), | |
| 347 | base->GetPitchByIndex(0), overlay->GetPitchByIndex(0), mask->GetPitchByIndex(0), | ||
| 348 | w, h, opacity_f); | ||
| 349 | } | ||
| 350 | // Chroma planes: outer loop = rows, inner = planes. | ||
| 351 | // Scratch filled once per row, reused for all active chroma planes (U and V). | ||
| 352 | ✗ | if (planeindex_to >= 1) { | |
| 353 | ✗ | MaskMode chroma_maskMode = MASK444; | |
| 354 | ✗ | if (vi_internal.IsYV411()) | |
| 355 | ✗ | chroma_maskMode = MASK411; | |
| 356 | ✗ | else if (vi_internal.Is420()) | |
| 357 | ✗ | chroma_maskMode = (placement == PLACEMENT_MPEG1) ? MASK420 : (placement == PLACEMENT_TOPLEFT) ? MASK420_TOPLEFT : MASK420_MPEG2; | |
| 358 | ✗ | else if (vi_internal.Is422()) | |
| 359 | ✗ | chroma_maskMode = (placement == PLACEMENT_MPEG1) ? MASK422 : (placement == PLACEMENT_TOPLEFT) ? MASK422_TOPLEFT : MASK422_MPEG2; | |
| 360 | |||
| 361 | ✗ | const int xws = base->xSubSamplingShifts[1]; | |
| 362 | ✗ | const int yhs = base->ySubSamplingShifts[1]; | |
| 363 | ✗ | const int chroma_w = (xws > 0) ? ((base->xAccum() & ((1 << xws) - 1)) + w + (1 << xws) - 1) >> xws : w; | |
| 364 | ✗ | const int chroma_h = (yhs > 0) ? ((base->yAccum() & ((1 << yhs) - 1)) + h + (1 << yhs) - 1) >> yhs : h; | |
| 365 | ✗ | const int luma_mask_pitch_floats = mask->GetPitchByIndex(0) / (int)sizeof(float); | |
| 366 | ✗ | const int luma_mask_advance = (chroma_maskMode == MASK420 || chroma_maskMode == MASK420_MPEG2 || chroma_maskMode == MASK420_TOPLEFT) | |
| 367 | ✗ | ? luma_mask_pitch_floats * 2 : luma_mask_pitch_floats; | |
| 368 | ✗ | const int scratch_pitch = chroma_w * (int)sizeof(float); | |
| 369 | ✗ | std::vector<float> scratch(chroma_w); | |
| 370 | |||
| 371 | // Mutable row pointers for each active chroma plane (p=1, p=2) | ||
| 372 | ✗ | BYTE* basep[2] = { base->GetPtrByIndex(1), base->GetPtrByIndex(2) }; | |
| 373 | ✗ | const BYTE* ovlp [2] = { overlay->GetPtrByIndex(1), overlay->GetPtrByIndex(2) }; | |
| 374 | ✗ | const int base_pitch[2] = { base->GetPitchByIndex(1), base->GetPitchByIndex(2) }; | |
| 375 | ✗ | const int ovl_pitch [2] = { overlay->GetPitchByIndex(1), overlay->GetPitchByIndex(2) }; | |
| 376 | ✗ | const int n_planes = planeindex_to; // 1 or 2 active chroma planes (indices 0..n_planes-1) | |
| 377 | |||
| 378 | ✗ | const float* lmask = reinterpret_cast<const float*>(mask->GetPtrByIndex(0)); | |
| 379 | ✗ | const bool chroma_full_opacity = (opacity_f == 1.0f); | |
| 380 | #ifdef INTEL_INTRINSICS | ||
| 381 | ✗ | const bool use_avx2_rowprep_f = (cpuFlags & CPUF_AVX2) != 0; | |
| 382 | ✗ | const bool use_sse41_rowprep_f = (cpuFlags & CPUF_SSE4_1) != 0; | |
| 383 | #endif | ||
| 384 | #ifdef NEON_INTRINSICS | ||
| 385 | const bool use_neon_rowprep_f = (cpuFlags & CPUF_ARM_NEON) != 0; | ||
| 386 | #endif | ||
| 387 | ✗ | for (int y = 0; y < chroma_h; y++) { | |
| 388 | // Fill scratch once for this luma-mask row pair, baking opacity in. | ||
| 389 | #ifdef INTEL_INTRINSICS | ||
| 390 | ✗ | if (use_avx2_rowprep_f) { | |
| 391 | ✗ | if (chroma_full_opacity) | |
| 392 | ✗ | do_fill_chroma_row_float_avx2<true> (scratch, lmask, luma_mask_pitch_floats, chroma_w, chroma_maskMode); | |
| 393 | else | ||
| 394 | ✗ | do_fill_chroma_row_float_avx2<false>(scratch, lmask, luma_mask_pitch_floats, chroma_w, chroma_maskMode, opacity_f); | |
| 395 | ✗ | } else if (use_sse41_rowprep_f) { | |
| 396 | ✗ | if (chroma_full_opacity) | |
| 397 | ✗ | do_fill_chroma_row_float_sse41<true> (scratch, lmask, luma_mask_pitch_floats, chroma_w, chroma_maskMode); | |
| 398 | else | ||
| 399 | ✗ | do_fill_chroma_row_float_sse41<false>(scratch, lmask, luma_mask_pitch_floats, chroma_w, chroma_maskMode, opacity_f); | |
| 400 | } else | ||
| 401 | #elif defined(NEON_INTRINSICS) | ||
| 402 | if (use_neon_rowprep_f) { | ||
| 403 | if (chroma_full_opacity) | ||
| 404 | do_fill_chroma_row_float_neon<true>(scratch, lmask, luma_mask_pitch_floats, chroma_w, chroma_maskMode); | ||
| 405 | else | ||
| 406 | do_fill_chroma_row_float_neon<false>(scratch, lmask, luma_mask_pitch_floats, chroma_w, chroma_maskMode, opacity_f); | ||
| 407 | } else | ||
| 408 | #endif | ||
| 409 | { | ||
| 410 | ✗ | if (chroma_full_opacity) | |
| 411 | ✗ | do_fill_chroma_row_f<true> (scratch, lmask, luma_mask_pitch_floats, chroma_w, chroma_maskMode); | |
| 412 | else | ||
| 413 | ✗ | do_fill_chroma_row_f<false>(scratch, lmask, luma_mask_pitch_floats, chroma_w, chroma_maskMode, opacity_f); | |
| 414 | } | ||
| 415 | // Apply to each active chroma plane; opacity already baked — pass 1.0f. | ||
| 416 | ✗ | for (int i = 0; i < n_planes; i++) { | |
| 417 | ✗ | blend_fn_luma(basep[i], ovlp[i], (const BYTE*)scratch.data(), | |
| 418 | ✗ | base_pitch[i], ovl_pitch[i], scratch_pitch, chroma_w, 1, 1.0f); | |
| 419 | ✗ | basep[i] += base_pitch[i]; | |
| 420 | ✗ | ovlp [i] += ovl_pitch[i]; | |
| 421 | } | ||
| 422 | ✗ | lmask += luma_mask_advance; | |
| 423 | } | ||
| 424 | ✗ | } | |
| 425 | ✗ | return; | |
| 426 | } | ||
| 427 | |||
| 428 | // Normal path: greymask=false or non-subsampled — mask already at plane resolution. | ||
| 429 | ✗ | for (int p = planeindex_from; p <= planeindex_to; p++) { | |
| 430 | ✗ | masked_merge_float_fn_t* fn = (p == 0 || !use_chroma_fn) ? blend_fn_luma : blend_fn_chroma; | |
| 431 | ✗ | const int xws_p = base->xSubSamplingShifts[p]; | |
| 432 | ✗ | const int yhs_p = base->ySubSamplingShifts[p]; | |
| 433 | ✗ | const int plane_w = (xws_p > 0) ? ((base->xAccum() & ((1 << xws_p) - 1)) + w + (1 << xws_p) - 1) >> xws_p : w; | |
| 434 | ✗ | const int plane_h = (yhs_p > 0) ? ((base->yAccum() & ((1 << yhs_p) - 1)) + h + (1 << yhs_p) - 1) >> yhs_p : h; | |
| 435 | ✗ | fn(base->GetPtrByIndex(p), overlay->GetPtrByIndex(p), mask->GetPtrByIndex(p), | |
| 436 | base->GetPitchByIndex(p), overlay->GetPitchByIndex(p), mask->GetPitchByIndex(p), | ||
| 437 | plane_w, plane_h, opacity_f); | ||
| 438 | } | ||
| 439 | } | ||
| 440 | else { | ||
| 441 | // Integer path: opacity pre-scaled to [0, max_pixel_value]. | ||
| 442 | 6 | const int opacity_i = static_cast<int>(opacity_f * ((1 << bits_per_pixel) - 1) + 0.5f); | |
| 443 | 6 | masked_merge_fn_t* blend_fn_luma = get_overlay_blend_masked_fn(cpuFlags, false, placement, vi_internal); | |
| 444 | 3 | masked_merge_fn_t* blend_fn_chroma = | |
| 445 |
2/4void OL_BlendImage::BlendImageMask<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 29 → 30 taken 3 times.
✓ Branch 29 → 31 taken 3 times.
void OL_BlendImage::BlendImageMask<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 29 → 30 not taken.
✗ Branch 29 → 31 not taken.
|
6 | use_scratch_path ? blend_fn_luma |
| 446 | 3 | : get_overlay_blend_masked_fn(cpuFlags, true, placement, vi_internal); | |
| 447 | |||
| 448 |
2/4void OL_BlendImage::BlendImageMask<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 33 → 34 taken 3 times.
✓ Branch 33 → 110 taken 3 times.
void OL_BlendImage::BlendImageMask<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 33 → 34 not taken.
✗ Branch 33 → 110 not taken.
|
6 | if (use_scratch_path) { |
| 449 | // Luma plane (if applicable) | ||
| 450 |
1/4void OL_BlendImage::BlendImageMask<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 34 → 35 taken 3 times.
✗ Branch 34 → 42 not taken.
void OL_BlendImage::BlendImageMask<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 34 → 35 not taken.
✗ Branch 34 → 42 not taken.
|
3 | if (planeindex_from == 0) { |
| 451 | 6 | blend_fn_luma( | |
| 452 | 3 | base->GetPtrByIndex(0), overlay->GetPtrByIndex(0), mask->GetPtrByIndex(0), | |
| 453 | base->GetPitchByIndex(0), overlay->GetPitchByIndex(0), mask->GetPitchByIndex(0), | ||
| 454 | w, h, opacity_i, bits_per_pixel); | ||
| 455 | } | ||
| 456 | // Chroma planes: outer loop = rows, inner = planes. | ||
| 457 | // Scratch filled once per row, reused for all active chroma planes (U and V). | ||
| 458 |
1/4void OL_BlendImage::BlendImageMask<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 42 → 43 taken 3 times.
✗ Branch 42 → 109 not taken.
void OL_BlendImage::BlendImageMask<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 42 → 43 not taken.
✗ Branch 42 → 109 not taken.
|
3 | if (planeindex_to >= 1) { |
| 459 | 3 | MaskMode chroma_maskMode = MASK444; | |
| 460 |
2/8void OL_BlendImage::BlendImageMask<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 43 → 44 taken 3 times.
✗ Branch 43 → 138 not taken.
✗ Branch 44 → 45 not taken.
✓ Branch 44 → 46 taken 3 times.
void OL_BlendImage::BlendImageMask<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 43 → 44 not taken.
✗ Branch 43 → 138 not taken.
✗ Branch 44 → 45 not taken.
✗ Branch 44 → 46 not taken.
|
3 | if (vi_internal.IsYV411()) |
| 461 | ✗ | chroma_maskMode = MASK411; | |
| 462 |
3/8void OL_BlendImage::BlendImageMask<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 46 → 47 taken 3 times.
✗ Branch 46 → 138 not taken.
✓ Branch 47 → 48 taken 2 times.
✓ Branch 47 → 53 taken 1 time.
void OL_BlendImage::BlendImageMask<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 46 → 47 not taken.
✗ Branch 46 → 138 not taken.
✗ Branch 47 → 48 not taken.
✗ Branch 47 → 53 not taken.
|
3 | else if (vi_internal.Is420()) |
| 463 |
2/8void OL_BlendImage::BlendImageMask<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 48 → 49 taken 2 times.
✗ Branch 48 → 52 not taken.
✗ Branch 49 → 50 not taken.
✓ Branch 49 → 51 taken 2 times.
void OL_BlendImage::BlendImageMask<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 48 → 49 not taken.
✗ Branch 48 → 52 not taken.
✗ Branch 49 → 50 not taken.
✗ Branch 49 → 51 not taken.
|
2 | chroma_maskMode = (placement == PLACEMENT_MPEG1) ? MASK420 : (placement == PLACEMENT_TOPLEFT) ? MASK420_TOPLEFT : MASK420_MPEG2; |
| 464 |
2/8void OL_BlendImage::BlendImageMask<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 53 → 54 taken 1 time.
✗ Branch 53 → 138 not taken.
✓ Branch 54 → 55 taken 1 time.
✗ Branch 54 → 60 not taken.
void OL_BlendImage::BlendImageMask<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 53 → 54 not taken.
✗ Branch 53 → 138 not taken.
✗ Branch 54 → 55 not taken.
✗ Branch 54 → 60 not taken.
|
1 | else if (vi_internal.Is422()) |
| 465 |
2/8void OL_BlendImage::BlendImageMask<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 55 → 56 taken 1 time.
✗ Branch 55 → 59 not taken.
✗ Branch 56 → 57 not taken.
✓ Branch 56 → 58 taken 1 time.
void OL_BlendImage::BlendImageMask<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 55 → 56 not taken.
✗ Branch 55 → 59 not taken.
✗ Branch 56 → 57 not taken.
✗ Branch 56 → 58 not taken.
|
1 | chroma_maskMode = (placement == PLACEMENT_MPEG1) ? MASK422 : (placement == PLACEMENT_TOPLEFT) ? MASK422_TOPLEFT : MASK422_MPEG2; |
| 466 | |||
| 467 | 3 | const int xws = base->xSubSamplingShifts[1]; | |
| 468 | 3 | const int yhs = base->ySubSamplingShifts[1]; | |
| 469 |
1/4void OL_BlendImage::BlendImageMask<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 60 → 61 taken 3 times.
✗ Branch 60 → 63 not taken.
void OL_BlendImage::BlendImageMask<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 60 → 61 not taken.
✗ Branch 60 → 63 not taken.
|
3 | const int chroma_w = (xws > 0) ? ((base->xAccum() & ((1 << xws) - 1)) + w + (1 << xws) - 1) >> xws : w; |
| 470 |
2/4void OL_BlendImage::BlendImageMask<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 64 → 65 taken 2 times.
✓ Branch 64 → 67 taken 1 time.
void OL_BlendImage::BlendImageMask<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 64 → 65 not taken.
✗ Branch 64 → 67 not taken.
|
3 | const int chroma_h = (yhs > 0) ? ((base->yAccum() & ((1 << yhs) - 1)) + h + (1 << yhs) - 1) >> yhs : h; |
| 471 | 3 | const int luma_mask_pitch_pixels = mask->GetPitchByIndex(0) / (int)sizeof(pixel_t); | |
| 472 |
3/8void OL_BlendImage::BlendImageMask<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 70 → 71 taken 1 time.
✓ Branch 70 → 72 taken 2 times.
✗ Branch 71 → 72 not taken.
✓ Branch 71 → 73 taken 1 time.
void OL_BlendImage::BlendImageMask<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 70 → 71 not taken.
✗ Branch 70 → 72 not taken.
✗ Branch 71 → 72 not taken.
✗ Branch 71 → 73 not taken.
|
3 | const int luma_mask_advance = (chroma_maskMode == MASK420 || chroma_maskMode == MASK420_MPEG2 || chroma_maskMode == MASK420_TOPLEFT) |
| 473 |
1/4void OL_BlendImage::BlendImageMask<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 69 → 70 taken 3 times.
✗ Branch 69 → 72 not taken.
void OL_BlendImage::BlendImageMask<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 69 → 70 not taken.
✗ Branch 69 → 72 not taken.
|
3 | ? luma_mask_pitch_pixels * 2 : luma_mask_pitch_pixels; |
| 474 | 3 | const int scratch_pitch = chroma_w * (int)sizeof(pixel_t); | |
| 475 |
1/4void OL_BlendImage::BlendImageMask<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 76 → 77 taken 3 times.
✗ Branch 76 → 133 not taken.
void OL_BlendImage::BlendImageMask<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 76 → 77 not taken.
✗ Branch 76 → 133 not taken.
|
3 | std::vector<pixel_t> scratch(chroma_w); |
| 476 | |||
| 477 | // Mutable row pointers for each active chroma plane (p=1, p=2) | ||
| 478 | 3 | BYTE* basep[2] = { base->GetPtrByIndex(1), base->GetPtrByIndex(2) }; | |
| 479 | 3 | const BYTE* ovlp [2] = { overlay->GetPtrByIndex(1), overlay->GetPtrByIndex(2) }; | |
| 480 | 3 | const int base_pitch[2] = { base->GetPitchByIndex(1), base->GetPitchByIndex(2) }; | |
| 481 | 3 | const int ovl_pitch [2] = { overlay->GetPitchByIndex(1), overlay->GetPitchByIndex(2) }; | |
| 482 | 3 | const int n_planes = planeindex_to; // 1 or 2 active chroma planes (indices 0..n_planes-1) | |
| 483 | |||
| 484 | 3 | const pixel_t* lmask = reinterpret_cast<const pixel_t*>(mask->GetPtrByIndex(0)); | |
| 485 | 3 | const int max_pixel_value = (1 << bits_per_pixel) - 1; | |
| 486 | 3 | const MagicDiv mag = get_magic_div(bits_per_pixel); | |
| 487 | 3 | const int half_val = max_pixel_value / 2; | |
| 488 | 3 | const bool chroma_full_opacity = (opacity_i == max_pixel_value); | |
| 489 | #ifdef INTEL_INTRINSICS | ||
| 490 | 3 | const bool use_avx2_rowprep = (cpuFlags & CPUF_AVX2) != 0; | |
| 491 | 3 | const bool use_sse41_rowprep = (cpuFlags & CPUF_SSE4_1) != 0; | |
| 492 | #endif | ||
| 493 | #ifdef NEON_INTRINSICS | ||
| 494 | const bool use_neon_rowprep = (cpuFlags & CPUF_ARM_NEON) != 0; | ||
| 495 | #endif | ||
| 496 | |||
| 497 |
2/4void OL_BlendImage::BlendImageMask<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 106 → 89 taken 9 times.
✓ Branch 106 → 107 taken 3 times.
void OL_BlendImage::BlendImageMask<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 106 → 89 not taken.
✗ Branch 106 → 107 not taken.
|
12 | for (int y = 0; y < chroma_h; y++) { |
| 498 | // Fill scratch once for this luma-mask row pair, baking opacity in. | ||
| 499 | #ifdef INTEL_INTRINSICS | ||
| 500 |
1/4void OL_BlendImage::BlendImageMask<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 89 → 90 taken 9 times.
✗ Branch 89 → 93 not taken.
void OL_BlendImage::BlendImageMask<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 89 → 90 not taken.
✗ Branch 89 → 93 not taken.
|
9 | if (use_avx2_rowprep) { |
| 501 |
1/4void OL_BlendImage::BlendImageMask<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 90 → 91 not taken.
✓ Branch 90 → 92 taken 9 times.
void OL_BlendImage::BlendImageMask<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 90 → 91 not taken.
✗ Branch 90 → 92 not taken.
|
9 | if (chroma_full_opacity) |
| 502 | ✗ | do_fill_chroma_row_avx2<pixel_t, true> (scratch, lmask, luma_mask_pitch_pixels, chroma_w, chroma_maskMode); | |
| 503 | else | ||
| 504 |
1/4void OL_BlendImage::BlendImageMask<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 92 → 100 taken 9 times.
✗ Branch 92 → 136 not taken.
void OL_BlendImage::BlendImageMask<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 92 → 100 not taken.
✗ Branch 92 → 136 not taken.
|
9 | do_fill_chroma_row_avx2<pixel_t, false>(scratch, lmask, luma_mask_pitch_pixels, chroma_w, chroma_maskMode, opacity_i, half_val, mag); |
| 505 | ✗ | } else if (use_sse41_rowprep) { | |
| 506 | ✗ | if (chroma_full_opacity) | |
| 507 | ✗ | do_fill_chroma_row_sse41<pixel_t, true> (scratch, lmask, luma_mask_pitch_pixels, chroma_w, chroma_maskMode); | |
| 508 | else | ||
| 509 | ✗ | do_fill_chroma_row_sse41<pixel_t, false>(scratch, lmask, luma_mask_pitch_pixels, chroma_w, chroma_maskMode, opacity_i, half_val, mag); | |
| 510 | } else | ||
| 511 | #elif defined(NEON_INTRINSICS) | ||
| 512 | if (use_neon_rowprep) { | ||
| 513 | if (chroma_full_opacity) | ||
| 514 | do_fill_chroma_row_neon<pixel_t, true>(scratch, lmask, luma_mask_pitch_pixels, chroma_w, chroma_maskMode); | ||
| 515 | else | ||
| 516 | do_fill_chroma_row_neon<pixel_t, false>(scratch, lmask, luma_mask_pitch_pixels, chroma_w, chroma_maskMode, opacity_i, half_val, mag); | ||
| 517 | } | ||
| 518 | else | ||
| 519 | #endif | ||
| 520 | { | ||
| 521 | ✗ | if (chroma_full_opacity) | |
| 522 | ✗ | do_fill_chroma_row<pixel_t, true> (scratch, lmask, luma_mask_pitch_pixels, chroma_w, chroma_maskMode); | |
| 523 | else | ||
| 524 | ✗ | do_fill_chroma_row<pixel_t, false>(scratch, lmask, luma_mask_pitch_pixels, chroma_w, chroma_maskMode, opacity_i, half_val, mag); | |
| 525 | } | ||
| 526 | // Apply to each active chroma plane; opacity already baked — pass max_pixel_value. | ||
| 527 |
2/4void OL_BlendImage::BlendImageMask<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 104 → 101 taken 18 times.
✓ Branch 104 → 105 taken 9 times.
void OL_BlendImage::BlendImageMask<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 104 → 101 not taken.
✗ Branch 104 → 105 not taken.
|
27 | for (int i = 0; i < n_planes; i++) { |
| 528 |
1/4void OL_BlendImage::BlendImageMask<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 102 → 103 taken 18 times.
✗ Branch 102 → 136 not taken.
void OL_BlendImage::BlendImageMask<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 102 → 103 not taken.
✗ Branch 102 → 136 not taken.
|
18 | blend_fn_luma(basep[i], ovlp[i], (const BYTE*)scratch.data(), |
| 529 | 18 | base_pitch[i], ovl_pitch[i], scratch_pitch, chroma_w, 1, max_pixel_value, bits_per_pixel); | |
| 530 | 18 | basep[i] += base_pitch[i]; | |
| 531 | 18 | ovlp [i] += ovl_pitch[i]; | |
| 532 | } | ||
| 533 | 9 | lmask += luma_mask_advance; | |
| 534 | } | ||
| 535 | 3 | } | |
| 536 | 3 | return; | |
| 537 | } | ||
| 538 | |||
| 539 | // Normal path: greymask=false or non-subsampled — mask already at plane resolution. | ||
| 540 |
2/4void OL_BlendImage::BlendImageMask<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 131 → 111 taken 9 times.
✓ Branch 131 → 132 taken 3 times.
void OL_BlendImage::BlendImageMask<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 131 → 111 not taken.
✗ Branch 131 → 132 not taken.
|
12 | for (int p = planeindex_from; p <= planeindex_to; p++) { |
| 541 |
3/8void OL_BlendImage::BlendImageMask<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 111 → 112 taken 6 times.
✓ Branch 111 → 113 taken 3 times.
✗ Branch 112 → 113 not taken.
✓ Branch 112 → 114 taken 6 times.
void OL_BlendImage::BlendImageMask<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 111 → 112 not taken.
✗ Branch 111 → 113 not taken.
✗ Branch 112 → 113 not taken.
✗ Branch 112 → 114 not taken.
|
9 | masked_merge_fn_t* fn = (p == 0 || !use_chroma_fn) ? blend_fn_luma : blend_fn_chroma; |
| 542 | 9 | const int xws_p = base->xSubSamplingShifts[p]; | |
| 543 | 9 | const int yhs_p = base->ySubSamplingShifts[p]; | |
| 544 |
1/4void OL_BlendImage::BlendImageMask<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 115 → 116 not taken.
✓ Branch 115 → 118 taken 9 times.
void OL_BlendImage::BlendImageMask<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 115 → 116 not taken.
✗ Branch 115 → 118 not taken.
|
9 | const int plane_w = (xws_p > 0) ? ((base->xAccum() & ((1 << xws_p) - 1)) + w + (1 << xws_p) - 1) >> xws_p : w; |
| 545 |
1/4void OL_BlendImage::BlendImageMask<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 119 → 120 not taken.
✓ Branch 119 → 122 taken 9 times.
void OL_BlendImage::BlendImageMask<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 119 → 120 not taken.
✗ Branch 119 → 122 not taken.
|
9 | const int plane_h = (yhs_p > 0) ? ((base->yAccum() & ((1 << yhs_p) - 1)) + h + (1 << yhs_p) - 1) >> yhs_p : h; |
| 546 | 9 | fn(base->GetPtrByIndex(p), overlay->GetPtrByIndex(p), mask->GetPtrByIndex(p), | |
| 547 | base->GetPitchByIndex(p), overlay->GetPitchByIndex(p), mask->GetPitchByIndex(p), | ||
| 548 | plane_w, plane_h, opacity_i, bits_per_pixel); | ||
| 549 | } | ||
| 550 | } | ||
| 551 | } | ||
| 552 | |||
| 553 | template<typename pixel_t> | ||
| 554 | 7 | void OL_BlendImage::BlendImage(ImageOverlayInternal* base, ImageOverlayInternal* overlay) { | |
| 555 | 7 | int w = base->w(); | |
| 556 | 7 | int h = base->h(); | |
| 557 | |||
| 558 | 7 | const int pixelsize = sizeof(pixel_t); | |
| 559 | |||
| 560 | 7 | int planeindex_from = 0; | |
| 561 | 7 | int planeindex_to = 0; | |
| 562 | |||
| 563 |
1/6void OL_BlendImage::BlendImage<float>(ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 8 not taken.
void OL_BlendImage::BlendImage<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 4 → 5 taken 7 times.
✗ Branch 4 → 8 not taken.
void OL_BlendImage::BlendImage<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 8 not taken.
|
7 | if (of_mode == OF_Blend) { |
| 564 | 7 | planeindex_from = 0; | |
| 565 |
1/6void OL_BlendImage::BlendImage<float>(ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 7 not taken.
void OL_BlendImage::BlendImage<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 7 times.
void OL_BlendImage::BlendImage<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 7 not taken.
|
7 | planeindex_to = greyscale ? 0 : 2; |
| 566 | } | ||
| 567 | ✗ | else if (of_mode == OF_Luma) { | |
| 568 | ✗ | planeindex_from = 0; | |
| 569 | ✗ | planeindex_to = 0; | |
| 570 | } | ||
| 571 | ✗ | else if (of_mode == OF_Chroma) { | |
| 572 | ✗ | if (greyscale) | |
| 573 | ✗ | return; | |
| 574 | ✗ | planeindex_from = 1; | |
| 575 | ✗ | planeindex_to = 2; | |
| 576 | } | ||
| 577 | |||
| 578 | // opacity == 0 was also an early-out case | ||
| 579 |
2/6void OL_BlendImage::BlendImage<float>(ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 14 → 15 not taken.
✗ Branch 14 → 31 not taken.
void OL_BlendImage::BlendImage<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 14 → 15 taken 1 time.
✓ Branch 14 → 31 taken 6 times.
void OL_BlendImage::BlendImage<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 14 → 15 not taken.
✗ Branch 14 → 31 not taken.
|
7 | if (opacity == 256) { |
| 580 |
2/6void OL_BlendImage::BlendImage<float>(ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 30 → 16 not taken.
✗ Branch 30 → 64 not taken.
void OL_BlendImage::BlendImage<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 30 → 16 taken 3 times.
✓ Branch 30 → 59 taken 1 time.
void OL_BlendImage::BlendImage<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 30 → 16 not taken.
✗ Branch 30 → 59 not taken.
|
4 | for (int p = planeindex_from; p <= planeindex_to; p++) { |
| 581 | 3 | const int xws_p = base->xSubSamplingShifts[p]; | |
| 582 | 3 | const int yhs_p = base->ySubSamplingShifts[p]; | |
| 583 |
1/6void OL_BlendImage::BlendImage<float>(ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 16 → 17 not taken.
✗ Branch 16 → 19 not taken.
void OL_BlendImage::BlendImage<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 19 taken 3 times.
void OL_BlendImage::BlendImage<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 16 → 17 not taken.
✗ Branch 16 → 19 not taken.
|
3 | const int plane_w = (xws_p > 0) ? ((base->xAccum() & ((1 << xws_p) - 1)) + w + (1 << xws_p) - 1) >> xws_p : w; |
| 584 |
1/6void OL_BlendImage::BlendImage<float>(ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 20 → 21 not taken.
✗ Branch 20 → 23 not taken.
void OL_BlendImage::BlendImage<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 23 taken 3 times.
void OL_BlendImage::BlendImage<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 20 → 21 not taken.
✗ Branch 20 → 23 not taken.
|
3 | const int plane_h = (yhs_p > 0) ? ((base->yAccum() & ((1 << yhs_p) - 1)) + h + (1 << yhs_p) - 1) >> yhs_p : h; |
| 585 | 3 | env->BitBlt(base->GetPtrByIndex(p), base->GetPitchByIndex(p), overlay->GetPtrByIndex(p), overlay->GetPitchByIndex(p), plane_w * pixelsize, plane_h); | |
| 586 | } | ||
| 587 | } | ||
| 588 | else { | ||
| 589 | 6 | overlay_blend_plane_masked_opacity_t* blend_fn = nullptr; | |
| 590 | |||
| 591 | #ifdef INTEL_INTRINSICS | ||
| 592 | ✗ | if (pixelsize == 4 && (env->GetCPUFlags() & CPUF_AVX2)) { | |
| 593 | ✗ | blend_fn = overlay_blend_weighted_float_avx2; | |
| 594 | } | ||
| 595 | ✗ | else if (pixelsize == 4 && (env->GetCPUFlags() & CPUF_SSE2)) { | |
| 596 | ✗ | blend_fn = overlay_blend_weighted_float_sse2; | |
| 597 | } | ||
| 598 |
1/6void OL_BlendImage::BlendImage<float>(ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 38 → 39 not taken.
✗ Branch 38 → 40 not taken.
void OL_BlendImage::BlendImage<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 33 → 34 taken 6 times.
✗ Branch 33 → 35 not taken.
void OL_BlendImage::BlendImage<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 33 → 34 not taken.
✗ Branch 33 → 35 not taken.
|
6 | else if (env->GetCPUFlags() & CPUF_AVX2) { |
| 599 | 6 | blend_fn = overlay_blend_weighted_avx2; // handles all integer depths, width-exact | |
| 600 | } | ||
| 601 | ✗ | else if (env->GetCPUFlags() & CPUF_SSE2) { | |
| 602 | ✗ | blend_fn = overlay_blend_weighted_sse2; // handles all integer depths | |
| 603 | } | ||
| 604 | else | ||
| 605 | #endif // INTEL_INTRINSICS | ||
| 606 | #ifdef NEON_INTRINSICS | ||
| 607 | if (pixelsize == 4 && (env->GetCPUFlags() & CPUF_ARM_NEON)) { | ||
| 608 | blend_fn = overlay_blend_neon_weighted_float_wrap; | ||
| 609 | } | ||
| 610 | else if (env->GetCPUFlags() & CPUF_ARM_NEON) { | ||
| 611 | blend_fn = overlay_blend_neon_weighted_wrap; | ||
| 612 | } | ||
| 613 | else | ||
| 614 | #endif // NEON_INTRINSICS | ||
| 615 | { | ||
| 616 | // pure C | ||
| 617 | ✗ | if (bits_per_pixel == 32) blend_fn = overlay_blend_weighted_float_c; | |
| 618 | ✗ | else blend_fn = overlay_blend_weighted_c; | |
| 619 | } | ||
| 620 | // end of new, float precision inside masked overlays | ||
| 621 | |||
| 622 |
1/6void OL_BlendImage::BlendImage<float>(ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 46 → 47 not taken.
✗ Branch 46 → 48 not taken.
void OL_BlendImage::BlendImage<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 41 → 42 not taken.
✓ Branch 41 → 43 taken 6 times.
void OL_BlendImage::BlendImage<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 41 → 42 not taken.
✗ Branch 41 → 43 not taken.
|
6 | if (blend_fn == nullptr) |
| 623 | ✗ | env->ThrowError("Blend: no valid internal function"); | |
| 624 | |||
| 625 |
2/6void OL_BlendImage::BlendImage<float>(ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 63 → 49 not taken.
✗ Branch 63 → 64 not taken.
void OL_BlendImage::BlendImage<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 58 → 44 taken 18 times.
✓ Branch 58 → 59 taken 6 times.
void OL_BlendImage::BlendImage<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 58 → 44 not taken.
✗ Branch 58 → 59 not taken.
|
24 | for (int p = planeindex_from; p <= planeindex_to; p++) { |
| 626 | 18 | const int xws_p = base->xSubSamplingShifts[p]; | |
| 627 | 18 | const int yhs_p = base->ySubSamplingShifts[p]; | |
| 628 |
2/6void OL_BlendImage::BlendImage<float>(ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 49 → 50 not taken.
✗ Branch 49 → 52 not taken.
void OL_BlendImage::BlendImage<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 44 → 45 taken 6 times.
✓ Branch 44 → 47 taken 12 times.
void OL_BlendImage::BlendImage<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 44 → 45 not taken.
✗ Branch 44 → 47 not taken.
|
18 | const int plane_w = (xws_p > 0) ? ((base->xAccum() & ((1 << xws_p) - 1)) + w + (1 << xws_p) - 1) >> xws_p : w; |
| 629 |
2/6void OL_BlendImage::BlendImage<float>(ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 53 → 54 not taken.
✗ Branch 53 → 56 not taken.
void OL_BlendImage::BlendImage<unsigned char>(ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 48 → 49 taken 4 times.
✓ Branch 48 → 51 taken 14 times.
void OL_BlendImage::BlendImage<unsigned short>(ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 48 → 49 not taken.
✗ Branch 48 → 51 not taken.
|
18 | const int plane_h = (yhs_p > 0) ? ((base->yAccum() & ((1 << yhs_p) - 1)) + h + (1 << yhs_p) - 1) >> yhs_p : h; |
| 630 | // no mask ptr | ||
| 631 | 36 | blend_fn( | |
| 632 | 18 | base->GetPtrByIndex(p), overlay->GetPtrByIndex(p), nullptr, | |
| 633 | base->GetPitchByIndex(p), overlay->GetPitchByIndex(p), 0, | ||
| 634 | plane_w, plane_h, opacity_f, | ||
| 635 | bits_per_pixel); | ||
| 636 | } | ||
| 637 | |||
| 638 | } | ||
| 639 | } | ||
| 640 |