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