GCC Code Coverage Report


Directory: avs_core/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 32.6% 152 / 0 / 466
Functions: 50.0% 5 / 0 / 10
Branches: 20.1% 29 / 0 / 144

filters/overlay/OF_exclusion.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 #include <avs/minmax.h>
40
41 #include <stdint.h>
42 #include <type_traits>
43
44 1 void OL_ExclusionImage::DoBlendImageMask(ImageOverlayInternal* base, ImageOverlayInternal* overlay, ImageOverlayInternal* mask) {
45 1 const bool fullOpacity = (opacity_f == 1.0f); // becomes a template switch
46
1/2
✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 6 not taken.
1 if (bits_per_pixel == 8) {
47
1/2
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 5 not taken.
1 if (fullOpacity) BlendImageMask<uint8_t, true, true>(base, overlay, mask);
48 else BlendImageMask<uint8_t, true, false>(base, overlay, mask);
49 } else if(bits_per_pixel <= 16) {
50 if (fullOpacity) BlendImageMask<uint16_t, true, true>(base, overlay, mask);
51 else BlendImageMask<uint16_t, true, false>(base, overlay, mask);
52 }
53 //else if(bits_per_pixel == 32)
54 // BlendImageMask<float>(base, overlay, mask);
55 1 }
56
57 3 void OL_ExclusionImage::DoBlendImage(ImageOverlayInternal* base, ImageOverlayInternal* overlay) {
58 3 const bool fullOpacity = (opacity_f == 1.0f); // becomes a template switch
59
1/2
✓ Branch 2 → 3 taken 3 times.
✗ Branch 2 → 6 not taken.
3 if (bits_per_pixel == 8) {
60
2/2
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 5 taken 1 time.
3 if (fullOpacity) BlendImageMask<uint8_t, false, true>(base, overlay, nullptr);
61 1 else BlendImageMask<uint8_t, false, false>(base, overlay, nullptr);
62 } else if(bits_per_pixel <= 16) {
63 if (fullOpacity) BlendImageMask<uint16_t, false, true>(base, overlay, nullptr);
64 else BlendImageMask<uint16_t, false, false>(base, overlay, nullptr);
65 }
66 //else if(bits_per_pixel == 32)
67 // BlendImage<float>(base, overlay);
68 3 }
69
70
71 template<typename pixel_t, bool maskMode, bool fullOpacity>
72 4 void OL_ExclusionImage::BlendImageMask(ImageOverlayInternal* base, ImageOverlayInternal* overlay, ImageOverlayInternal* mask) {
73 4 pixel_t* baseY = reinterpret_cast<pixel_t*>(base->GetPtr(PLANAR_Y));
74 4 pixel_t* baseU = reinterpret_cast<pixel_t*>(base->GetPtr(PLANAR_U));
75 4 pixel_t* baseV = reinterpret_cast<pixel_t*>(base->GetPtr(PLANAR_V));
76
77 4 pixel_t* ovY = reinterpret_cast<pixel_t*>(overlay->GetPtr(PLANAR_Y));
78 4 pixel_t* ovU = reinterpret_cast<pixel_t*>(overlay->GetPtr(PLANAR_U));
79 4 pixel_t* ovV = reinterpret_cast<pixel_t*>(overlay->GetPtr(PLANAR_V));
80
81 pixel_t* maskY;
82 pixel_t* maskU;
83 pixel_t* maskV;
84 if constexpr (maskMode) {
85 1 maskY = reinterpret_cast<pixel_t*>(mask->GetPtr(PLANAR_Y));
86 1 maskU = reinterpret_cast<pixel_t*>(mask->GetPtr(PLANAR_U));
87 1 maskV = reinterpret_cast<pixel_t*>(mask->GetPtr(PLANAR_V));
88 }
89 else {
90 3 maskY = nullptr;
91 3 maskU = nullptr;
92 3 maskV = nullptr;
93 }
94
95 4 const int half_pixel_value = (sizeof(pixel_t) == 1) ? 128 : (1 << (bits_per_pixel - 1));
96 4 const int max_pixel_value = (sizeof(pixel_t) == 1) ? 255 : (1 << bits_per_pixel) - 1;
97 4 const int xor_mask = max_pixel_value;
98 4 const int pixel_range = max_pixel_value + 1; // used only by the overbright/superdark multiplier below
99 4 const int SHIFT = (sizeof(pixel_t) == 1) ? 5 : 5 + (bits_per_pixel - 8);
100 4 const int over32 = (1 << SHIFT); // 32
101 4 const int basepitch = (base->pitch) / sizeof(pixel_t);
102 4 const int overlaypitch = (overlay->pitch) / sizeof(pixel_t);
103 int maskpitch;
104 if constexpr (maskMode) {
105 1 maskpitch = (mask->pitch) / sizeof(pixel_t);
106 }
107 else {
108 3 maskpitch = 0;
109 }
110
111 4 const MagicDiv magic = get_magic_div(bits_per_pixel);
112
113 // fullOpacity is a template parameter (based on opacity_f==1.0f check)
114 // Formulas below containing opacity_i are hopefully compiler optimized.
115 // opacity_i on the max_pixel_value scale gives finer opacity granularity at >8-bit
116 // than the old fixed 0..256 scale.
117 4 const int opacity_i = fullOpacity ? max_pixel_value : (int)(opacity_f * max_pixel_value + 0.5f);
118 4 const int rounder = max_pixel_value / 2;
119
120 4 int w = base->w();
121 4 int h = base->h();
122
123
6/16
void OL_ExclusionImage::BlendImageMask<unsigned char, false, false>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 52 → 12 taken 3 times.
✓ Branch 52 → 53 taken 1 time.
void OL_ExclusionImage::BlendImageMask<unsigned char, false, true>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 46 → 12 taken 5 times.
✓ Branch 46 → 47 taken 2 times.
void OL_ExclusionImage::BlendImageMask<unsigned char, true, false>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 61 → 15 not taken.
✗ Branch 61 → 62 not taken.
void OL_ExclusionImage::BlendImageMask<unsigned char, true, true>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 55 → 15 taken 2 times.
✓ Branch 55 → 56 taken 1 time.
void OL_ExclusionImage::BlendImageMask<unsigned short, false, false>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 52 → 12 not taken.
✗ Branch 52 → 53 not taken.
void OL_ExclusionImage::BlendImageMask<unsigned short, false, true>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 46 → 12 not taken.
✗ Branch 46 → 47 not taken.
void OL_ExclusionImage::BlendImageMask<unsigned short, true, false>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 61 → 15 not taken.
✗ Branch 61 → 62 not taken.
void OL_ExclusionImage::BlendImageMask<unsigned short, true, true>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 55 → 15 not taken.
✗ Branch 55 → 56 not taken.
14 for (int y = 0; y < h; y++) {
124
6/16
void OL_ExclusionImage::BlendImageMask<unsigned char, false, false>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 50 → 13 taken 15 times.
✓ Branch 50 → 51 taken 3 times.
void OL_ExclusionImage::BlendImageMask<unsigned char, false, true>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 44 → 13 taken 23 times.
✓ Branch 44 → 45 taken 5 times.
void OL_ExclusionImage::BlendImageMask<unsigned char, true, false>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 59 → 16 not taken.
✗ Branch 59 → 60 not taken.
void OL_ExclusionImage::BlendImageMask<unsigned char, true, true>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✓ Branch 53 → 16 taken 8 times.
✓ Branch 53 → 54 taken 2 times.
void OL_ExclusionImage::BlendImageMask<unsigned short, false, false>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 50 → 13 not taken.
✗ Branch 50 → 51 not taken.
void OL_ExclusionImage::BlendImageMask<unsigned short, false, true>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 44 → 13 not taken.
✗ Branch 44 → 45 not taken.
void OL_ExclusionImage::BlendImageMask<unsigned short, true, false>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 59 → 16 not taken.
✗ Branch 59 → 60 not taken.
void OL_ExclusionImage::BlendImageMask<unsigned short, true, true>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 53 → 16 not taken.
✗ Branch 53 → 54 not taken.
56 for (int x = 0; x < w; x++) {
125 // "Exclusion" formula: base+ov-2*base*ov/max_pixel_value
126 // Use int64_t for intermediate calculations: (base^xor)*ov + (ov^xor)*base is not uint32_t-safe.
127 // ~2*max_pixel_value^2
128 // Note: unlike Invert, this keeps xor-ing even for U and V, nevertheless this is an artistic filter
129 // So we don't care.
130 46 int64_t ovYx = ovY[x];
131 46 int Y = (int)((((int64_t)(baseY[x] ^ xor_mask)) * ovYx + (int64_t)(ovYx ^ xor_mask) * baseY[x]) / max_pixel_value);
132 46 int U = (int)((((int64_t)(baseU[x] ^ xor_mask)) * ovYx + (int64_t)(ovYx ^ xor_mask) * baseU[x]) / max_pixel_value);
133 46 int V = (int)((((int64_t)(baseV[x] ^ xor_mask)) * ovYx + (int64_t)(ovYx ^ xor_mask) * baseV[x]) / max_pixel_value);
134 if constexpr (!(fullOpacity && !maskMode)) {
135 // eff on the max_pixel_value scale; mask == max_pixel_value when absent.
136 // No sign problems here unlike at OF_softhardlight
137 uint32_t effY, effU, effV; // effective masks/opacity/their combinations
138 if constexpr (maskMode) {
139 if constexpr (fullOpacity) {
140 8 effY = maskY[x];
141 8 effU = maskU[x];
142 8 effV = maskV[x];
143 }
144 else {
145 effY = magic_div_rt<pixel_t>((uint32_t)maskY[x] * (uint32_t)opacity_i + rounder, magic);
146 effU = magic_div_rt<pixel_t>((uint32_t)maskU[x] * (uint32_t)opacity_i + rounder, magic);
147 effV = magic_div_rt<pixel_t>((uint32_t)maskV[x] * (uint32_t)opacity_i + rounder, magic);
148 }
149 }
150 else {
151 15 effY = (uint32_t)opacity_i;
152 15 effU = (uint32_t)opacity_i;
153 15 effV = (uint32_t)opacity_i;
154 }
155 23 Y = magic_div_rt<pixel_t>((uint32_t)Y * effY + (max_pixel_value - effY) * (uint32_t)baseY[x] + rounder, magic);
156 23 U = magic_div_rt<pixel_t>((uint32_t)U * effU + (max_pixel_value - effU) * (uint32_t)baseU[x] + rounder, magic);
157 23 V = magic_div_rt<pixel_t>((uint32_t)V * effV + (max_pixel_value - effV) * (uint32_t)baseV[x] + rounder, magic);
158 }
159
3/16
void OL_ExclusionImage::BlendImageMask<unsigned char, false, false>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 19 → 20 not taken.
✓ Branch 19 → 26 taken 15 times.
void OL_ExclusionImage::BlendImageMask<unsigned char, false, true>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 20 taken 23 times.
void OL_ExclusionImage::BlendImageMask<unsigned char, true, false>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 28 → 29 not taken.
✗ Branch 28 → 35 not taken.
void OL_ExclusionImage::BlendImageMask<unsigned char, true, true>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 22 → 23 not taken.
✓ Branch 22 → 29 taken 8 times.
void OL_ExclusionImage::BlendImageMask<unsigned short, false, false>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 19 → 20 not taken.
✗ Branch 19 → 26 not taken.
void OL_ExclusionImage::BlendImageMask<unsigned short, false, true>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 13 → 14 not taken.
✗ Branch 13 → 20 not taken.
void OL_ExclusionImage::BlendImageMask<unsigned short, true, false>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 28 → 29 not taken.
✗ Branch 28 → 35 not taken.
void OL_ExclusionImage::BlendImageMask<unsigned short, true, true>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 22 → 23 not taken.
✗ Branch 22 → 29 not taken.
46 if (Y > max_pixel_value) { // Apply overbrightness to UV
160 int multiplier = max(0, pixel_range + over32 - Y); // 0 to 32
161 U = ((U * (multiplier)) + (half_pixel_value * (over32 - multiplier))) >> SHIFT;
162 V = ((V * (multiplier)) + (half_pixel_value * (over32 - multiplier))) >> SHIFT;
163 Y = max_pixel_value;
164 }
165
3/16
void OL_ExclusionImage::BlendImageMask<unsigned char, false, false>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 26 → 27 not taken.
✓ Branch 26 → 33 taken 15 times.
void OL_ExclusionImage::BlendImageMask<unsigned char, false, true>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 27 taken 23 times.
void OL_ExclusionImage::BlendImageMask<unsigned char, true, false>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 35 → 36 not taken.
✗ Branch 35 → 42 not taken.
void OL_ExclusionImage::BlendImageMask<unsigned char, true, true>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 29 → 30 not taken.
✓ Branch 29 → 36 taken 8 times.
void OL_ExclusionImage::BlendImageMask<unsigned short, false, false>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 26 → 27 not taken.
✗ Branch 26 → 33 not taken.
void OL_ExclusionImage::BlendImageMask<unsigned short, false, true>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 20 → 21 not taken.
✗ Branch 20 → 27 not taken.
void OL_ExclusionImage::BlendImageMask<unsigned short, true, false>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 35 → 36 not taken.
✗ Branch 35 → 42 not taken.
void OL_ExclusionImage::BlendImageMask<unsigned short, true, true>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 29 → 30 not taken.
✗ Branch 29 → 36 not taken.
46 else if (Y < 0) { // Apply superdark to UV
166 int multiplier = min(-Y, over32); // 0 to 32
167 U = ((U * (over32 - multiplier)) + (half_pixel_value * (multiplier))) >> SHIFT;
168 V = ((V * (over32 - multiplier)) + (half_pixel_value * (multiplier))) >> SHIFT;
169 Y = 0;
170 }
171
3/16
void OL_ExclusionImage::BlendImageMask<unsigned char, false, false>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 33 → 34 not taken.
✓ Branch 33 → 35 taken 15 times.
void OL_ExclusionImage::BlendImageMask<unsigned char, false, true>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 27 → 28 not taken.
✓ Branch 27 → 29 taken 23 times.
void OL_ExclusionImage::BlendImageMask<unsigned char, true, false>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 42 → 43 not taken.
✗ Branch 42 → 44 not taken.
void OL_ExclusionImage::BlendImageMask<unsigned char, true, true>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 36 → 37 not taken.
✓ Branch 36 → 38 taken 8 times.
void OL_ExclusionImage::BlendImageMask<unsigned short, false, false>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 33 → 34 not taken.
✗ Branch 33 → 35 not taken.
void OL_ExclusionImage::BlendImageMask<unsigned short, false, true>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 27 → 28 not taken.
✗ Branch 27 → 29 not taken.
void OL_ExclusionImage::BlendImageMask<unsigned short, true, false>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 42 → 43 not taken.
✗ Branch 42 → 44 not taken.
void OL_ExclusionImage::BlendImageMask<unsigned short, true, true>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 36 → 37 not taken.
✗ Branch 36 → 38 not taken.
46 baseY[x] = (pixel_t)Y;
172
3/16
void OL_ExclusionImage::BlendImageMask<unsigned char, false, false>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 41 → 42 not taken.
✓ Branch 41 → 43 taken 15 times.
void OL_ExclusionImage::BlendImageMask<unsigned char, false, true>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 35 → 36 not taken.
✓ Branch 35 → 37 taken 23 times.
void OL_ExclusionImage::BlendImageMask<unsigned char, true, false>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 50 → 51 not taken.
✗ Branch 50 → 52 not taken.
void OL_ExclusionImage::BlendImageMask<unsigned char, true, true>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 44 → 45 not taken.
✓ Branch 44 → 46 taken 8 times.
void OL_ExclusionImage::BlendImageMask<unsigned short, false, false>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 41 → 42 not taken.
✗ Branch 41 → 43 not taken.
void OL_ExclusionImage::BlendImageMask<unsigned short, false, true>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 35 → 36 not taken.
✗ Branch 35 → 37 not taken.
void OL_ExclusionImage::BlendImageMask<unsigned short, true, false>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 50 → 51 not taken.
✗ Branch 50 → 52 not taken.
void OL_ExclusionImage::BlendImageMask<unsigned short, true, true>(ImageOverlayInternal*, ImageOverlayInternal*, ImageOverlayInternal*):
✗ Branch 44 → 45 not taken.
✗ Branch 44 → 46 not taken.
46 baseU[x] = (pixel_t)clamp(U, 0, max_pixel_value);
173 46 baseV[x] = (pixel_t)clamp(V, 0, max_pixel_value);
174 }
175 10 baseY += basepitch;
176 10 baseU += basepitch;
177 10 baseV += basepitch;
178
179 10 ovY += overlaypitch;
180 10 ovU += overlaypitch;
181 10 ovV += overlaypitch;
182
183 if constexpr (maskMode) {
184 2 maskY += maskpitch;
185 2 maskU += maskpitch;
186 2 maskV += maskpitch;
187 }
188 }
189 4 }
190
191