GCC Code Coverage Report


Directory: avs_core/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 0.9% 139 / 0 / 15838
Functions: 1.2% 5 / 0 / 406
Branches: 3.1% 227 / 0 / 7363

convert/convert_bits.cpp
Line Branch Exec Source
1 // Avisynth v2.5. Copyright 2002-2009 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 #include "convert_bits.h"
36 #ifdef INTEL_INTRINSICS
37 #include "intel/convert_bits_sse.h"
38 #include "intel/convert_bits_avx2.h"
39 #endif
40 #include "convert_helper.h"
41
42 #include <avs/alignment.h>
43 #include <avs/minmax.h>
44 #include <avs/config.h>
45 #include <tuple>
46 #include <map>
47 #include <algorithm>
48 #include <vector>
49
50 #ifdef AVS_WINDOWS
51 #include <avs/win.h>
52 #else
53 #include <avs/posix.h>
54 #endif
55
56 // for odd dither bit differences, we still take even size but
57 // correction values are halved (shifted by 1)
58
59 // repeated 8x for sse size 16
60 const BYTE dither2x2a_data[4] = {
61 0, 1,
62 1, 0,
63 };
64 // cycle: 2
65 alignas(16) const BYTE dither2x2a_data_sse2[2 * 16] = {
66 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
67 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0
68 };
69
70 // e.g. 10->8 bits
71 // repeated 8x for sse size 16
72 const BYTE dither2x2_data[4] = {
73 0, 2,
74 3, 1,
75 };
76 // cycle: 2
77 alignas(16) const BYTE dither2x2_data_sse2[2 * 16] = {
78 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2,
79 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1
80 };
81
82 // e.g. 8->5 bits
83 const BYTE dither4x4a_data[16] = {
84 0, 4, 1, 5,
85 6, 2, 7, 3,
86 1, 5, 0, 4,
87 7, 3, 6, 2
88 };
89 // cycle: 4
90 alignas(16) const BYTE dither4x4a_data_sse2[4 * 16] = {
91 0, 4, 1, 5, 0, 4, 1, 5, 0, 4, 1, 5, 0, 4, 1, 5,
92 6, 2, 7, 3, 6, 2, 7, 3, 6, 2, 7, 3, 6, 2, 7, 3,
93 1, 5, 0, 4, 1, 5, 0, 4, 1, 5, 0, 4, 1, 5, 0, 4,
94 7, 3, 6, 2, 7, 3, 6, 2, 7, 3, 6, 2, 7, 3, 6, 2,
95 };
96
97 // e.g. 12->8 bits
98 const BYTE dither4x4_data[16] = {
99 0, 8, 2, 10,
100 12, 4, 14, 6,
101 3, 11, 1, 9,
102 15, 7, 13, 5
103 };
104 // cycle: 4
105 alignas(16) const BYTE dither4x4_data_sse2[4 * 16] = {
106 0, 8, 2, 10, 0, 8, 2, 10, 0, 8, 2, 10, 0, 8, 2, 10,
107 12, 4, 14, 6, 12, 4, 14, 6, 12, 4, 14, 6, 12, 4, 14, 6,
108 3, 11, 1, 9, 3, 11, 1, 9, 3, 11, 1, 9, 3, 11, 1, 9,
109 15, 7, 13, 5, 15, 7, 13, 5, 15, 7, 13, 5, 15, 7, 13, 5
110 };
111
112 // e.g. 14->9 bits
113 extern const BYTE dither8x8a_data[8][8] = {
114 { 0, 16, 4, 20, 1, 17, 5, 21}, /* 8x8 Bayer ordered dithering pattern */
115 {24, 8, 28, 12, 25, 9, 29, 13},
116 { 6, 22, 2, 18, 7, 23, 3, 19},
117 {30, 14, 26, 10, 31, 15, 27, 11},
118 { 1, 17, 5, 21, 0, 16, 4, 20},
119 {25, 9, 29, 13, 24, 8, 28, 12},
120 { 7, 23, 3, 19, 6, 22, 2, 18},
121 {31, 15, 27, 11, 30, 14, 26, 10}
122 };
123 // cycle: 8
124 alignas(16) const BYTE dither8x8a_data_sse2[8][16] = {
125 { 0, 16, 4, 20, 1, 17, 5, 21, 0, 16, 4, 20, 1, 17, 5, 21 },
126 { 24, 8, 28, 12, 25, 9, 29, 13, 24, 8, 28, 12, 25, 9, 29, 13 },
127 { 6, 22, 2, 18, 7, 23, 3, 19, 6, 22, 2, 18, 7, 23, 3, 19 },
128 { 30, 14, 26, 10, 31, 15, 27, 11, 30, 14, 26, 10, 31, 15, 27, 11 },
129 { 1, 17, 5, 21, 0, 16, 4, 20, 1, 17, 5, 21, 0, 16, 4, 20 },
130 { 25, 9, 29, 13, 24, 8, 28, 12, 25, 9, 29, 13, 24, 8, 28, 12 },
131 { 7, 23, 3, 19, 6, 22, 2, 18, 7, 23, 3, 19, 6, 22, 2, 18 },
132 { 31, 15, 27, 11, 30, 14, 26, 10, 31, 15, 27, 11, 30, 14, 26, 10 }
133 };
134
135 // e.g. 14->8 bits
136 extern const BYTE dither8x8_data[8][8] = {
137 { 0, 32, 8, 40, 2, 34, 10, 42},
138 {48, 16, 56, 24, 50, 18, 58, 26},
139 {12, 44, 4, 36, 14, 46, 6, 38},
140 {60, 28, 52, 20, 62, 30, 54, 22},
141 { 3, 35, 11, 43, 1, 33, 9, 41},
142 {51, 19, 59, 27, 49, 17, 57, 25},
143 {15, 47, 7, 39, 13, 45, 5, 37},
144 {63, 31, 55, 23, 61, 29, 53, 21}
145 };
146 // cycle: 8
147 alignas(16) const BYTE dither8x8_data_sse2[8][16] = {
148 { 0, 32, 8, 40, 2, 34, 10, 42, 0, 32, 8, 40, 2, 34, 10, 42 },
149 { 48, 16, 56, 24, 50, 18, 58, 26, 48, 16, 56, 24, 50, 18, 58, 26 },
150 { 12, 44, 4, 36, 14, 46, 6, 38, 12, 44, 4, 36, 14, 46, 6, 38 },
151 { 60, 28, 52, 20, 62, 30, 54, 22, 60, 28, 52, 20, 62, 30, 54, 22 },
152 { 3, 35, 11, 43, 1, 33, 9, 41, 3, 35, 11, 43, 1, 33, 9, 41 },
153 { 51, 19, 59, 27, 49, 17, 57, 25, 51, 19, 59, 27, 49, 17, 57, 25 },
154 { 15, 47, 7, 39, 13, 45, 5, 37, 15, 47, 7, 39, 13, 45, 5, 37 },
155 { 63, 31, 55, 23, 61, 29, 53, 21, 63, 31, 55, 23, 61, 29, 53, 21 }
156 };
157
158 // e.g. 16->9 or 8->1 bits
159 // cycle: 16x. No special 16 byte sse2
160 alignas(16) const BYTE dither16x16a_data[16][16] = {
161 { 0, 96, 24,120, 6,102, 30,126, 1, 97, 25,121, 7,103, 31,127 },
162 { 64, 32, 88, 56, 70, 38, 94, 62, 65, 33, 89, 57, 71, 39, 95, 63 },
163 { 16,112, 8,104, 22,118, 14,110, 17,113, 9,105, 23,119, 15,111 },
164 { 80, 48, 72, 40, 86, 54, 78, 46, 81, 49, 73, 41, 87, 55, 79, 47 },
165 { 4,100, 28,124, 2, 98, 26,122, 5,101, 29,125, 3, 99, 27,123 },
166 { 68, 36, 92, 60, 66, 34, 90, 58, 69, 37, 93, 61, 67, 35, 91, 59 },
167 { 20,116, 12,108, 18,114, 10,106, 21,117, 13,109, 19,115, 11,107 },
168 { 84, 52, 76, 44, 82, 50, 74, 42, 85, 53, 77, 45, 83, 51, 75, 43 },
169 { 1, 97, 25,121, 7,103, 31,127, 0, 96, 24,120, 6,102, 30,126 },
170 { 75, 33, 89, 57, 71, 39, 95, 63, 64, 32, 88, 56, 70, 38, 94, 62 },
171 { 17,113, 9,105, 23,119, 15,111, 16,112, 8,104, 22,118, 14,110 },
172 { 81, 49, 73, 41, 87, 55, 79, 47, 80, 48, 72, 40, 86, 54, 78, 46 },
173 { 5,101, 29,125, 3, 99, 27,123, 4,100, 28,124, 2, 98, 26,122 },
174 { 69, 37, 93, 61, 67, 35, 91, 59, 68, 36, 92, 60, 66, 34, 90, 58 },
175 { 21,117, 13,109, 19,115, 11,107, 20,116, 12,108, 18,114, 10,106 },
176 { 85, 53, 77, 45, 83, 51, 75, 43, 84, 52, 76, 44, 82, 50, 74, 42 }
177 };
178
179 // 16->8
180 // cycle: 16x. No special 16 byte sse2
181 alignas(16) const BYTE dither16x16_data[16][16] = {
182 { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 },
183 { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 },
184 { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 },
185 { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 },
186 { 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247 },
187 { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 },
188 { 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 },
189 { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 },
190 { 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253 },
191 { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 },
192 { 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 },
193 { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 },
194 { 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245 },
195 { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 },
196 { 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 },
197 { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 }
198 };
199
200
201 template<typename pixel_t_s, typename pixel_t_d, bool chroma, bool fulls, bool fulld, bool TEMPLATE_NEED_BACKSCALE, bool TEMPLATE_LOW_DITHER_BITDEPTH>
202 static void do_convert_ordered_dither_uint_c(const BYTE* srcp8, BYTE* dstp8, int src_rowsize, int src_height, int src_pitch, int dst_pitch, int source_bitdepth, int target_bitdepth, int dither_target_bitdepth)
203 {
204 const pixel_t_s* srcp = reinterpret_cast<const pixel_t_s*>(srcp8);
205 pixel_t_d* dstp = reinterpret_cast<pixel_t_d*>(dstp8);
206 dst_pitch = dst_pitch / sizeof(pixel_t_d);
207
208 src_pitch = src_pitch / sizeof(pixel_t_s);
209 const int src_width = src_rowsize / sizeof(pixel_t_s);
210
211 // helps compiler optimization
212 if constexpr (sizeof(pixel_t_s) == 1)
213 source_bitdepth = 8;
214 if constexpr (sizeof(pixel_t_d) == 1) {
215 target_bitdepth = 8;
216 if (!TEMPLATE_NEED_BACKSCALE) {
217 dither_target_bitdepth = 8;
218 }
219 }
220
221 const int max_pixel_value_target = (1 << target_bitdepth) - 1;
222 const int max_pixel_value_dithered = (1 << dither_target_bitdepth) - 1;
223 // precheck ensures:
224 // target_bitdepth >= dither_target_bitdepth
225 // source_bitdepth - dither_target_bitdepth <= 8 (max precalculated table is 16x16)
226 const bool odd_diff = (source_bitdepth - dither_target_bitdepth) & 1;
227 const int dither_bit_diff = (source_bitdepth - dither_target_bitdepth);
228 const int dither_order = (dither_bit_diff + 1) / 2;
229 const int dither_mask = (1 << dither_order) - 1; // 9,10=2 11,12=4 13,14=8 15,16=16
230 // 10->8: 0x01 (2x2)
231 // 11->8: 0x03 (4x4)
232 // 12->8: 0x03 (4x4)
233 // 14->8: 0x07 (8x8)
234 // 16->8: 0x0F (16x16)
235 const BYTE* matrix;
236 switch (dither_order) {
237 case 1: matrix = reinterpret_cast<const BYTE*>(odd_diff ? dither2x2a_data : dither2x2_data); break;
238 case 2: matrix = reinterpret_cast<const BYTE*>(odd_diff ? dither4x4a_data : dither4x4_data); break;
239 case 3: matrix = reinterpret_cast<const BYTE*>(odd_diff ? dither8x8a_data : dither8x8_data); break;
240 case 4: matrix = reinterpret_cast<const BYTE*>(odd_diff ? dither16x16a_data : dither16x16_data); break;
241 default: return; // n/a
242 }
243
244 const int bitdiff_between_dither_and_target = target_bitdepth - dither_target_bitdepth;
245 assert(TEMPLATE_NEED_BACKSCALE == (target_bitdepth != dither_target_bitdepth)); // dither to x, target to y
246
247 assert(TEMPLATE_LOW_DITHER_BITDEPTH == (dither_target_bitdepth < 8));
248 // e.g. instead of 0,1 => -0.5,+0.5; 0,1,2,3 => -1.5,-0.5,0.5,1.5
249 const float half_maxcorr_value = ((1 << dither_bit_diff) - 1) / 2.0f;
250
251 const int source_max = (1 << source_bitdepth) - 1;
252 //-----------------------
253 // When calculating src_pixel, src and dst are of the same bit depth
254 bits_conv_constants d;
255 get_bits_conv_constants(d, chroma, fulls, fulld, source_bitdepth, source_bitdepth);
256
257 auto dst_offset_plus_round = d.dst_offset + 0.5f;
258 constexpr auto src_pixel_min = 0;
259 const auto src_pixel_max = source_max;
260 const float mul_factor_backfromlowdither = (float)max_pixel_value_target / max_pixel_value_dithered;
261 //-----------------------
262
263 for (int y = 0; y < src_height; y++)
264 {
265 int _y = (y & dither_mask) << dither_order; // ordered dither
266 for (int x = 0; x < src_width; x++)
267 {
268 const int corr = matrix[_y | (x & dither_mask)];
269
270 int src_pixel = srcp[x];
271
272 if constexpr(fulls != fulld) {
273 const float val = (srcp[x] - d.src_offset_i) * d.mul_factor + dst_offset_plus_round;
274 src_pixel = clamp((int)val, src_pixel_min, src_pixel_max);
275 }
276
277 int new_pixel;
278 if (TEMPLATE_LOW_DITHER_BITDEPTH) {
279 // accurate dither: +/-
280 // accurately positioned to the center
281 const float corr_f = corr - half_maxcorr_value;
282 new_pixel = (int)(src_pixel + corr_f) >> dither_bit_diff;
283 }
284 else
285 new_pixel = ((src_pixel + corr) >> dither_bit_diff);
286
287 // scale back to the required bit depth
288 if constexpr (TEMPLATE_NEED_BACKSCALE) { // dither to x, target to y
289 new_pixel = min(new_pixel, max_pixel_value_dithered);
290 // Interesting problem of dither_bits==1 (or in general at small dither_bits)
291 // After simple slli 0,1 becomes 0,128, we'd expect 0,255 instead. So we make cosmetics.
292 if (TEMPLATE_LOW_DITHER_BITDEPTH) {
293 new_pixel = (int)(new_pixel * mul_factor_backfromlowdither + 0.5f);
294 }
295 else {
296 new_pixel = new_pixel << bitdiff_between_dither_and_target;
297 }
298 // dither_bits
299 // 1 0,1 => 0,128 => 0,255
300 // 2 0,1,2,3 => 0,64,128,192 => 0,?,?,255
301 // 3 0,...,7 => 0,32,...,224 => 0,?,?,255
302 // 4 0,..,15 => 0,16,...,240 => 0,?,?,255
303 // 5 0,..,31 => 0,8,....,248 => 0,?,?,255
304 // 6 0,..,63 => 0,4,....,252 => 0,?,?,255
305 // 7 0,.,127 => 0,2. ..,254 => 0,?,?,255
306 }
307 dstp[x] = (pixel_t_d)(max(min((int)new_pixel, max_pixel_value_target),0));
308 }
309 dstp += dst_pitch;
310 srcp += src_pitch;
311 }
312 }
313
314 template<typename pixel_t_s, typename pixel_t_d, bool chroma, bool fulls, bool fulld>
315 static void convert_ordered_dither_uint_c(const BYTE* srcp8, BYTE* dstp8, int src_rowsize, int src_height, int src_pitch, int dst_pitch, int source_bitdepth, int target_bitdepth, int dither_target_bitdepth)
316 {
317 const bool need_backscale = target_bitdepth != dither_target_bitdepth; // dither to x, target to y
318 const bool low_dither_bitdepth = dither_target_bitdepth < 8; // 1-7 bits dither targets, need_backscale is always true, since 8 bit format is the minimum
319 if (need_backscale) {
320 if (low_dither_bitdepth)
321 do_convert_ordered_dither_uint_c<pixel_t_s, pixel_t_d, chroma, fulls, fulld, true, true>(srcp8, dstp8, src_rowsize, src_height, src_pitch, dst_pitch, source_bitdepth, target_bitdepth, dither_target_bitdepth);
322 else
323 do_convert_ordered_dither_uint_c<pixel_t_s, pixel_t_d, chroma, fulls, fulld, true, false>(srcp8, dstp8, src_rowsize, src_height, src_pitch, dst_pitch, source_bitdepth, target_bitdepth, dither_target_bitdepth);
324 }
325 else {
326 do_convert_ordered_dither_uint_c<pixel_t_s, pixel_t_d, chroma, fulls, fulld, false, false>(srcp8, dstp8, src_rowsize, src_height, src_pitch, dst_pitch, source_bitdepth, target_bitdepth, dither_target_bitdepth);
327 }
328 }
329
330 // idea borrowed from fmtConv
331 #define FS_OPTIMIZED_SERPENTINE_COEF
332
333 template<int direction>
334 static AVS_FORCEINLINE void diffuse_floyd(int err, int &nextError, int *error_ptr)
335 {
336 #if defined (FS_OPTIMIZED_SERPENTINE_COEF)
337 const int e1 = 0;
338 const int e3 = (err * 4 + 8) >> 4;
339 #else
340 const int e1 = (err + 8) >> 4;
341 const int e3 = (err * 3 + 8) >> 4;
342 #endif
343 const int e5 = (err * 5 + 8) >> 4;
344 const int e7 = err - e1 - e3 - e5;
345
346 nextError = error_ptr[direction];
347 error_ptr[-direction] += e3;
348 error_ptr[0] += e5;
349 error_ptr[direction] = e1;
350 nextError += e7;
351 }
352
353 #if 0
354 template<int direction>
355 static AVS_FORCEINLINE void diffuse_floyd_f(float err, float& nextError, float* error_ptr)
356 {
357 #if defined (FS_OPTIMIZED_SERPENTINE_COEF)
358 const float e1 = 0;
359 const float e3 = err * (4.0f / 16);
360 #else
361 const float e1 = err * (1.0f / 16);
362 const float e3 = err * (3.0f / 16);
363 #endif
364 const float e5 = err * (5.0f / 16);
365 const float e7 = err * (7.0f / 16);
366
367 nextError = error_ptr[direction];
368 error_ptr[-direction] += e3;
369 error_ptr[0] += e5;
370 error_ptr[direction] = e1;
371 nextError += e7;
372 }
373 #endif
374
375 // optimization helper: TEMPLATE_DITHER_BIT_DIFF if not <0 then hold value for frequently used differences from 16->8
376 // 2nd helper: TEMPLATE_LOW_DITHER_BITDEPTH
377 // 3rd helper: source_bitdepth_special
378 template<typename pixel_t_s, typename pixel_t_d, bool chroma, bool fulls, bool fulld, int TEMPLATE_DITHER_BIT_DIFF, bool TEMPLATE_LOW_DITHER_BITDEPTH, int SOURCE_BITDEPTH_SPECIAL>
379 static void do_convert_uint_floyd_c(const BYTE* srcp8, BYTE* dstp8, int src_rowsize, int src_height, int src_pitch, int dst_pitch, int source_bitdepth, int target_bitdepth, int dither_target_bitdepth)
380 {
381 if constexpr (SOURCE_BITDEPTH_SPECIAL > 0) {
382 // called with >0 values only for special cases like 16 to 8, 16 to 10 and 10 to 8
383 // Hugely helps the optimizers
384 source_bitdepth = SOURCE_BITDEPTH_SPECIAL;
385 }
386 if constexpr (TEMPLATE_DITHER_BIT_DIFF > 0) {
387 assert(TEMPLATE_DITHER_BIT_DIFF == (source_bitdepth - dither_target_bitdepth));
388 assert(target_bitdepth == dither_target_bitdepth);
389 dither_target_bitdepth = source_bitdepth - TEMPLATE_DITHER_BIT_DIFF;
390 target_bitdepth = dither_target_bitdepth;
391 // seems that direct shift with known constant bits is really quicker than shift by 'cl'.
392 // Dithering from 16 to 10 bit: 109 vs 101 fps
393 // PF note: experienced the same with SIMD _mm_srl and _mm_srli in the other bit converter
394 }
395 const int DITHER_BIT_DIFF = TEMPLATE_DITHER_BIT_DIFF > 0 ? TEMPLATE_DITHER_BIT_DIFF : (source_bitdepth - dither_target_bitdepth);
396 assert(TEMPLATE_LOW_DITHER_BITDEPTH == (dither_target_bitdepth < 8)); // must match with dispatcher
397
398 const pixel_t_s* srcp = reinterpret_cast<const pixel_t_s*>(srcp8);
399 src_pitch = src_pitch / sizeof(pixel_t_s);
400 const int src_width = src_rowsize / sizeof(pixel_t_s);
401
402 pixel_t_d* dstp = reinterpret_cast<pixel_t_d*>(dstp8);
403 dst_pitch = dst_pitch / sizeof(pixel_t_d);
404
405 // perhaps helps compiler to optimize
406 if constexpr (sizeof(pixel_t_s) == 1)
407 source_bitdepth = 8;
408 if constexpr (sizeof(pixel_t_d) == 1)
409 target_bitdepth = 8;
410
411 const int max_pixel_value_target = (1 << target_bitdepth) - 1;
412 const int BITDIFF_BETWEEN_DITHER_AND_TARGET = DITHER_BIT_DIFF - (source_bitdepth - target_bitdepth);
413 const int max_pixel_value_dithered = (1 << dither_target_bitdepth) - 1;
414
415 std::vector<int> error_ptr_safe(1 + src_width + 1); // accumulated errors
416 int *error_ptr = &error_ptr_safe[1];
417
418 const int ROUNDER = 1 << (DITHER_BIT_DIFF - 1); // rounding
419 const int source_max = (1 << source_bitdepth) - 1;
420 //-----------------------
421 bits_conv_constants d;
422 get_bits_conv_constants(d, chroma, fulls, fulld, source_bitdepth, source_bitdepth);
423
424 auto dst_offset_plus_round = d.dst_offset + 0.5f;
425 constexpr auto src_pixel_min = 0;
426 const auto src_pixel_max = source_max;
427 const float mul_factor_backfromlowdither = (float)max_pixel_value_target / max_pixel_value_dithered;
428
429 int nextError = 0; // zero
430
431 for (int y = 0; y < src_height; y++)
432 {
433 // serpentine forward
434 if ((y & 1) == 0)
435 {
436 for (int x = 0; x < src_width; x++)
437 {
438 int err = nextError;
439 int src_pixel = srcp[x];
440
441 if constexpr (fulls != fulld) {
442 const float val = (src_pixel - d.src_offset_i) * d.mul_factor + dst_offset_plus_round;
443 src_pixel = clamp((int)val, src_pixel_min, src_pixel_max);
444 }
445
446 if (TEMPLATE_LOW_DITHER_BITDEPTH) {
447 // accurate dither: +/-
448 // accurately positioned to the center
449 err = err - (1 << (DITHER_BIT_DIFF - 1)); // signed
450 }
451 int sum = src_pixel + err;
452
453 int quantized = (sum + ROUNDER) >> (DITHER_BIT_DIFF);
454 err = sum - (quantized << DITHER_BIT_DIFF);
455 // Interesting problem of dither_bits==1 (or in general at small dither_bits)
456 // After simple slli 0,1 becomes 0,128, we'd expect 0,255 instead. So we make cosmetics.
457 if (TEMPLATE_LOW_DITHER_BITDEPTH) {
458 quantized = min(quantized, max_pixel_value_dithered);
459 quantized = (int)(quantized * mul_factor_backfromlowdither + 0.5f);
460 }
461 else {
462 quantized <<= BITDIFF_BETWEEN_DITHER_AND_TARGET;
463 }
464 int pix = max(min(max_pixel_value_target, quantized), 0); // clamp to target bit
465 dstp[x] = (pixel_t_d)pix;
466 diffuse_floyd<1>(err, nextError, &error_ptr[x]);
467 }
468 }
469 else {
470 // serpentine backward
471 for (int x = src_width - 1; x >= 0; --x)
472 {
473 int err = nextError;
474 int src_pixel = srcp[x];
475
476 if constexpr (fulls != fulld) {
477 const float val = (src_pixel - d.src_offset_i) * d.mul_factor + dst_offset_plus_round;
478 src_pixel = clamp((int)val, src_pixel_min, src_pixel_max);
479 }
480
481 if (TEMPLATE_LOW_DITHER_BITDEPTH) {
482 // accurate dither: +/-
483 // accurately positioned to the center
484 err = err - (1 << (DITHER_BIT_DIFF - 1)); // signed
485 }
486 int sum = src_pixel + err;
487
488 int quantized = (sum + ROUNDER) >> (DITHER_BIT_DIFF);
489 err = sum - (quantized << DITHER_BIT_DIFF);
490 // Interesting problem of dither_bits==1 (or in general at small dither_bits)
491 // After simple slli 0,1 becomes 0,128, we'd expect 0,255 instead. So we make cosmetics.
492 if (TEMPLATE_LOW_DITHER_BITDEPTH) {
493 quantized = min(quantized, max_pixel_value_dithered);
494 quantized = (int)(quantized * mul_factor_backfromlowdither + 0.5f);
495 }
496 else {
497 quantized <<= BITDIFF_BETWEEN_DITHER_AND_TARGET;
498 }
499 int pix = max(min(max_pixel_value_target, quantized), 0); // clamp to target bit
500 dstp[x] = (pixel_t_d)pix;
501 diffuse_floyd<-1>(err, nextError, &error_ptr[x]);
502 }
503 }
504 dstp += dst_pitch;
505 srcp += src_pitch;
506 }
507 }
508
509
510 template<typename pixel_t_s, typename pixel_t_d, bool chroma, bool fulls, bool fulld>
511 static void convert_uint_floyd_c(const BYTE* srcp8, BYTE* dstp8, int src_rowsize, int src_height, int src_pitch, int dst_pitch, int source_bitdepth, int target_bitdepth, int dither_target_bitdepth)
512 {
513 const int dither_bit_diff = source_bitdepth - dither_target_bitdepth;
514 const bool low_dither_bitdepth = dither_target_bitdepth < 8;
515 // extra internal template makes it quicker for ordinary non-artistic cases
516 // do not make templates for all 1-16 target bit combinations
517 if (low_dither_bitdepth) {
518 do_convert_uint_floyd_c<pixel_t_s, pixel_t_d, chroma, fulls, fulld, -1, true, -1>(srcp8, dstp8, src_rowsize, src_height, src_pitch, dst_pitch, source_bitdepth, target_bitdepth, dither_target_bitdepth);
519 }
520 else {
521 if (target_bitdepth == dither_target_bitdepth) {
522 // Specifically when source_bitdepth is known as well, it hugely helps optimization
523 // We treat special use cases 10->8, 16->10 and 16->8
524 switch (dither_bit_diff) {
525 case 2: // e.g. 10->8
526 if (source_bitdepth == 10)
527 do_convert_uint_floyd_c<pixel_t_s, pixel_t_d, chroma, fulls, fulld, 2, false, 10>(srcp8, dstp8, src_rowsize, src_height, src_pitch, dst_pitch, source_bitdepth, target_bitdepth, dither_target_bitdepth);
528 else
529 do_convert_uint_floyd_c<pixel_t_s, pixel_t_d, chroma, fulls, fulld, 2, false, -1>(srcp8, dstp8, src_rowsize, src_height, src_pitch, dst_pitch, source_bitdepth, target_bitdepth, dither_target_bitdepth);
530 break;
531 case 4: // e.g. 12->8
532 do_convert_uint_floyd_c<pixel_t_s, pixel_t_d, chroma, fulls, fulld, 4, false, -1>(srcp8, dstp8, src_rowsize, src_height, src_pitch, dst_pitch, source_bitdepth, target_bitdepth, dither_target_bitdepth);
533 break;
534 case 6: // e.g. 16->10, 14->8
535 // prevent invalid templates to generate
536 // like do_convert_uint_floyd_c<unsigned short,unsigned char,0,0,1,6,0,16> which would do 16->8 but dither to 10 bit.
537 if constexpr (sizeof(pixel_t_s) == 2 && sizeof(pixel_t_d) == 2) {
538 if (source_bitdepth == 16)
539 do_convert_uint_floyd_c<pixel_t_s, pixel_t_d, chroma, fulls, fulld, 6, false, 16>(srcp8, dstp8, src_rowsize, src_height, src_pitch, dst_pitch, source_bitdepth, target_bitdepth, dither_target_bitdepth);
540 else
541 do_convert_uint_floyd_c<pixel_t_s, pixel_t_d, chroma, fulls, fulld, 6, false, -1>(srcp8, dstp8, src_rowsize, src_height, src_pitch, dst_pitch, source_bitdepth, target_bitdepth, dither_target_bitdepth);
542 } else
543 do_convert_uint_floyd_c<pixel_t_s, pixel_t_d, chroma, fulls, fulld, 6, false, -1>(srcp8, dstp8, src_rowsize, src_height, src_pitch, dst_pitch, source_bitdepth, target_bitdepth, dither_target_bitdepth);
544 break;
545 case 8: // e.g. 16->8
546 if (sizeof(pixel_t_s) == 2 && source_bitdepth == 16)
547 do_convert_uint_floyd_c<pixel_t_s, pixel_t_d, chroma, fulls, fulld, 8, false, 16>(srcp8, dstp8, src_rowsize, src_height, src_pitch, dst_pitch, source_bitdepth, target_bitdepth, dither_target_bitdepth);
548 else
549 do_convert_uint_floyd_c<pixel_t_s, pixel_t_d, chroma, fulls, fulld, 8, false, -1>(srcp8, dstp8, src_rowsize, src_height, src_pitch, dst_pitch, source_bitdepth, target_bitdepth, dither_target_bitdepth);
550 break;
551 default: // difference is more than 8 or exotic dither to less than 8 bits, we accept 10-15% speed minus
552 do_convert_uint_floyd_c<pixel_t_s, pixel_t_d, chroma, fulls, fulld, -1, false, -1>(srcp8, dstp8, src_rowsize, src_height, src_pitch, dst_pitch, source_bitdepth, target_bitdepth, dither_target_bitdepth);
553 }
554 }
555 else {
556 do_convert_uint_floyd_c<pixel_t_s, pixel_t_d, chroma, fulls, fulld, -1, false, -1>(srcp8, dstp8, src_rowsize, src_height, src_pitch, dst_pitch, source_bitdepth, target_bitdepth, dither_target_bitdepth);
557 }
558 }
559 }
560
561 // float to 8-16 bits
562 template<typename pixel_t, bool chroma, bool fulls, bool fulld>
563 static void convert_32_to_uintN_c(const BYTE *srcp, BYTE *dstp, int src_rowsize, int src_height, int src_pitch, int dst_pitch, int source_bitdepth, int target_bitdepth, int dither_target_bitdepth)
564 {
565 const float *srcp0 = reinterpret_cast<const float *>(srcp);
566 pixel_t *dstp0 = reinterpret_cast<pixel_t *>(dstp);
567
568 src_pitch = src_pitch / sizeof(float);
569 dst_pitch = dst_pitch / sizeof(pixel_t);
570
571 const int src_width = src_rowsize / sizeof(float);
572
573 //-----------------------
574
575 bits_conv_constants d;
576 get_bits_conv_constants(d, chroma, fulls, fulld, source_bitdepth, target_bitdepth);
577
578 auto dst_offset_plus_round = d.dst_offset + 0.5f;
579 constexpr auto dst_pixel_min = 0;
580 const auto dst_pixel_max = (1 << target_bitdepth) - 1;
581
582 for(int y=0; y<src_height; y++)
583 {
584 for (int x = 0; x < src_width; x++)
585 {
586 const int pixel = (int)((srcp0[x] - d.src_offset) * d.mul_factor + dst_offset_plus_round);
587 dstp0[x] = pixel_t(clamp(pixel, dst_pixel_min, dst_pixel_max));
588 }
589 dstp0 += dst_pitch;
590 srcp0 += src_pitch;
591 }
592 }
593
594 // YUV: bit shift 8-16 <=> 8-16 bits
595 // shift right or left, depending on expandrange
596 template<typename pixel_t_s, typename pixel_t_d>
597 static void convert_uint_limited_c(const BYTE* srcp, BYTE* dstp, int src_rowsize, int src_height, int src_pitch, int dst_pitch, int source_bitdepth, int target_bitdepth, int dither_target_bitdepth)
598 {
599 const pixel_t_s* srcp0 = reinterpret_cast<const pixel_t_s*>(srcp);
600 pixel_t_d* dstp0 = reinterpret_cast<pixel_t_d*>(dstp);
601
602 src_pitch = src_pitch / sizeof(pixel_t_s);
603 dst_pitch = dst_pitch / sizeof(pixel_t_d);
604
605 const int src_width = src_rowsize / sizeof(pixel_t_s);
606
607 if (target_bitdepth > source_bitdepth) // expandrange
608 {
609 const int shift_bits = target_bitdepth - source_bitdepth;
610 for (int y = 0; y < src_height; y++)
611 {
612 for (int x = 0; x < src_width; x++) {
613 dstp0[x] = (pixel_t_d)(srcp0[x]) << shift_bits; // expand range. No clamp before, source is assumed to have valid range
614 }
615 dstp0 += dst_pitch;
616 srcp0 += src_pitch;
617 }
618 }
619 else
620 {
621 // reduce range
622 const int shift_bits = source_bitdepth - target_bitdepth;
623 const int round = 1 << (shift_bits - 1);
624
625 const pixel_t_s source_max = (1 << source_bitdepth) - 1;
626
627 for (int y = 0; y < src_height; y++)
628 {
629 const pixel_t_s* AVS_RESTRICT s = srcp0;
630 pixel_t_d* AVS_RESTRICT d = dstp0;
631
632 for (int x = 0; x < src_width; x++) {
633 int val = static_cast<int>(s[x]) + round;
634 if (val > source_max) val = source_max; // no saturated add in C
635 d[x] = static_cast<pixel_t_d>(val >> shift_bits);
636 }
637 dstp0 += dst_pitch;
638 srcp0 += src_pitch;
639 }
640 }
641 }
642
643 // chroma is special in full range
644 template<typename pixel_t_s, typename pixel_t_d, bool chroma, bool fulls, bool fulld>
645 static void convert_uint_c(const BYTE* srcp, BYTE* dstp, int src_rowsize, int src_height, int src_pitch, int dst_pitch, int source_bitdepth, int target_bitdepth, int dither_target_bitdepth)
646 {
647 // limited to limited is bitshift, see in other function
648 if constexpr (!fulls && !fulld) {
649 convert_uint_limited_c< pixel_t_s, pixel_t_d>(srcp, dstp, src_rowsize, src_height, src_pitch, dst_pitch, source_bitdepth, target_bitdepth, dither_target_bitdepth);
650 return;
651 }
652
653 const pixel_t_s* srcp0 = reinterpret_cast<const pixel_t_s*>(srcp);
654 pixel_t_d* dstp0 = reinterpret_cast<pixel_t_d*>(dstp);
655
656 src_pitch = src_pitch / sizeof(pixel_t_s);
657 dst_pitch = dst_pitch / sizeof(pixel_t_d);
658
659 const int src_width = src_rowsize / sizeof(pixel_t_s);
660
661 if constexpr (sizeof(pixel_t_s) == 1 && sizeof(pixel_t_d) == 2) {
662 if (fulls && fulld && !chroma && source_bitdepth == 8 && target_bitdepth == 16) {
663 // special case * 65535 / 255 = *257 exactly
664 for (int y = 0; y < src_height; y++)
665 {
666 for (int x = 0; x < src_width; x++)
667 {
668 dstp0[x] = (pixel_t_d)(srcp0[x] * 257);
669 }
670 dstp0 += dst_pitch;
671 srcp0 += src_pitch;
672 }
673 return;
674 }
675 }
676
677 const int target_max = (1 << target_bitdepth) - 1;
678
679 bits_conv_constants d;
680 get_bits_conv_constants(d, chroma, fulls, fulld, source_bitdepth, target_bitdepth);
681
682 auto dst_offset_plus_round = d.dst_offset + 0.5f;
683 constexpr auto target_min = 0;
684
685 for (int y = 0; y < src_height; y++) {
686 for (int x = 0; x < src_width; x++)
687 {
688 const float val = (srcp0[x] - d.src_offset_i) * d.mul_factor + dst_offset_plus_round;
689 dstp0[x] = clamp((int)val, target_min, target_max);
690 }
691
692 dstp0 += dst_pitch;
693 srcp0 += src_pitch;
694 }
695 }
696
697
698
699 // 8 bit to float, 16/14/12/10 bits to float
700 template<typename pixel_t, bool chroma, bool fulls, bool fulld>
701 static void convert_uintN_to_float_c(const BYTE *srcp, BYTE *dstp, int src_rowsize, int src_height, int src_pitch, int dst_pitch, int source_bitdepth, int target_bitdepth, int dither_target_bitdepth)
702 {
703 const pixel_t *srcp0 = reinterpret_cast<const pixel_t *>(srcp);
704 float *dstp0 = reinterpret_cast<float *>(dstp);
705
706 src_pitch = src_pitch / sizeof(pixel_t);
707 dst_pitch = dst_pitch / sizeof(float);
708
709 const int src_width = src_rowsize / sizeof(pixel_t);
710
711 //-----------------------
712 bits_conv_constants d;
713 get_bits_conv_constants(d, chroma, fulls, fulld, source_bitdepth, target_bitdepth);
714
715 for (int y = 0; y < src_height; y++)
716 {
717 for (int x = 0; x < src_width; x++)
718 {
719 const float pixel = (srcp0[x] - d.src_offset_i) * d.mul_factor + d.dst_offset;
720 dstp0[x] = pixel; // no clamp
721 }
722 dstp0 += dst_pitch;
723 srcp0 += src_pitch;
724 }
725 }
726
727 // float to float
728 template<bool chroma, bool fulls, bool fulld>
729 static void convert_float_to_float_c(const BYTE* srcp, BYTE* dstp, int src_rowsize, int src_height, int src_pitch, int dst_pitch, int source_bitdepth, int target_bitdepth, int dither_target_bitdepth)
730 {
731 // float is good if always full range. For historical reasons Avisynth has "limited" range float,
732 // which is simply a /255.0 reduction of original byte pixels
733 const float* srcp0 = reinterpret_cast<const float*>(srcp);
734 float* dstp0 = reinterpret_cast<float*>(dstp);
735
736 src_pitch = src_pitch / sizeof(float);
737 dst_pitch = dst_pitch / sizeof(float);
738
739 const int src_width = src_rowsize / sizeof(float);
740
741 //-----------------------
742 bits_conv_constants d;
743 get_bits_conv_constants(d, chroma, fulls, fulld, source_bitdepth, target_bitdepth);
744
745 for (int y = 0; y < src_height; y++)
746 {
747 for (int x = 0; x < src_width; x++)
748 {
749 const float pixel = (srcp0[x] - d.src_offset) * d.mul_factor + d.dst_offset;
750 dstp0[x] = pixel; // no clamp
751 }
752 dstp0 += dst_pitch;
753 srcp0 += src_pitch;
754 }
755 }
756
757 static void get_convert_32_to_uintN_functions(int target_bitdepth, bool fulls, bool fulld,
758 #ifdef INTEL_INTRINSICS
759 bool sse2, bool sse4, bool avx2,
760 #endif
761 BitDepthConvFuncPtr& conv_function, BitDepthConvFuncPtr& conv_function_chroma, BitDepthConvFuncPtr& conv_function_a)
762 {
763 // 32bit->8-16bits support fulls fulld
764 // pure C
765 #define convert_32_to_uintN_functions(uint_X_t) \
766 conv_function_a = convert_32_to_uintN_c<uint_X_t, false, true, true>; /* full-full */ \
767 if (fulls && fulld) { \
768 conv_function = convert_32_to_uintN_c<uint_X_t, false, true, true>; \
769 conv_function_chroma = convert_32_to_uintN_c<uint_X_t, true, true, true>; \
770 } \
771 else if (fulls && !fulld) { \
772 conv_function = convert_32_to_uintN_c<uint_X_t, false, true, false>; \
773 conv_function_chroma = convert_32_to_uintN_c<uint_X_t, true, true, false>; \
774 } \
775 else if (!fulls && fulld) { \
776 conv_function = convert_32_to_uintN_c<uint_X_t, false, false, true>; \
777 conv_function_chroma = convert_32_to_uintN_c<uint_X_t, true, false, true>; \
778 } \
779 else if (!fulls && !fulld) { \
780 conv_function = convert_32_to_uintN_c<uint_X_t, false, false, false>; \
781 conv_function_chroma = convert_32_to_uintN_c<uint_X_t, true, false, false>; \
782 }
783
784 #ifdef INTEL_INTRINSICS
785 #undef convert_32_to_uintN_functions
786
787 #define convert_32_to_uintN_functions(uint_X_t) \
788 conv_function_a = avx2 ? convert_32_to_uintN_avx2<uint_X_t, false, true, true> : sse4 ? convert_32_to_uintN_sse41<uint_X_t, false, true, true> : convert_32_to_uintN_c<uint_X_t, false, true, true>; /* full-full */ \
789 if (fulls && fulld) { \
790 conv_function = avx2 ? convert_32_to_uintN_avx2<uint_X_t, false, true, true> : sse4 ? convert_32_to_uintN_sse41<uint_X_t, false, true, true> : convert_32_to_uintN_c<uint_X_t, false, true, true>; \
791 conv_function_chroma = avx2 ? convert_32_to_uintN_avx2<uint_X_t, true, true, true> : sse4 ? convert_32_to_uintN_sse41<uint_X_t, true, true, true> : convert_32_to_uintN_c<uint_X_t, true, true, true>; \
792 } \
793 else if (fulls && !fulld) { \
794 conv_function = avx2 ? convert_32_to_uintN_avx2<uint_X_t, false, true, false> : sse4 ? convert_32_to_uintN_sse41<uint_X_t, false, true, false> : convert_32_to_uintN_c<uint_X_t, false, true, false>; \
795 conv_function_chroma = avx2 ? convert_32_to_uintN_avx2<uint_X_t, true, true, false> : sse4 ? convert_32_to_uintN_sse41<uint_X_t, true, true, false> : convert_32_to_uintN_c<uint_X_t, true, true, false>; \
796 } \
797 else if (!fulls && fulld) { \
798 conv_function = avx2 ? convert_32_to_uintN_avx2<uint_X_t, false, false, true> : sse4 ? convert_32_to_uintN_sse41<uint_X_t, false, false, true> : convert_32_to_uintN_c<uint_X_t, false, false, true>; \
799 conv_function_chroma = avx2 ? convert_32_to_uintN_avx2<uint_X_t, true, false, true> : sse4 ? convert_32_to_uintN_sse41<uint_X_t, true, false, true> : convert_32_to_uintN_c<uint_X_t, true, false, true>; \
800 } \
801 else if (!fulls && !fulld) { \
802 conv_function = avx2 ? convert_32_to_uintN_avx2<uint_X_t, false, false, false> : sse4 ? convert_32_to_uintN_sse41<uint_X_t, false, false, false> : convert_32_to_uintN_c<uint_X_t, false, false, false>; \
803 conv_function_chroma = avx2 ? convert_32_to_uintN_avx2<uint_X_t, true, false, false> : sse4 ? convert_32_to_uintN_sse41<uint_X_t, true, false, false> : convert_32_to_uintN_c<uint_X_t, true, false, false>; \
804 }
805 #endif
806
807 switch (target_bitdepth)
808 {
809 case 8:
810 convert_32_to_uintN_functions(uint8_t); // all variations of fulls fulld
811 break;
812 default:
813 // 10-16 bits
814 convert_32_to_uintN_functions(uint16_t); // all variations of fulls fulld
815 break;
816 }
817
818 #undef convert_32_to_uintN_functions
819 }
820
821 static void get_convert_float_to_float_functions(bool fulls, bool fulld,
822 BitDepthConvFuncPtr& conv_function, BitDepthConvFuncPtr& conv_function_chroma, BitDepthConvFuncPtr& conv_function_a)
823 {
824 // 32bit->32bits support fulls fulld, alpha is always full-full
825 conv_function_a = convert_float_to_float_c<false, true, true>; /* full-full */
826 if (fulls && fulld) {
827 conv_function = convert_float_to_float_c<false, true, true>;
828 conv_function_chroma = convert_float_to_float_c<true, true, true>;
829 }
830 else if (fulls && !fulld) {
831 conv_function = convert_float_to_float_c<false, true, false>;
832 conv_function_chroma = convert_float_to_float_c<true, true, false>;
833 }
834 else if (!fulls && fulld) { \
835 conv_function = convert_float_to_float_c<false, false, true>;
836 conv_function_chroma = convert_float_to_float_c<true, false, true>;
837 }
838 else if (!fulls && !fulld) {
839 conv_function = convert_float_to_float_c<false, false, false>;
840 conv_function_chroma = convert_float_to_float_c<true, false, false>;
841 }
842 }
843
844 static void get_convert_uintN_to_float_functions(int bits_per_pixel, bool fulls, bool fulld,
845 #ifdef INTEL_INTRINSICS
846 bool sse2, bool sse4, bool avx2,
847 #endif
848 BitDepthConvFuncPtr& conv_function, BitDepthConvFuncPtr& conv_function_chroma, BitDepthConvFuncPtr& conv_function_a)
849 {
850 // 8-16bit->32bits support fulls fulld, alpha is always full-full
851 #define convert_uintN_to_float_functions(uint_X_t) \
852 conv_function_a = convert_uintN_to_float_c<uint_X_t, false, true, true>; /* full-full */ \
853 if (fulls && fulld) { \
854 conv_function = convert_uintN_to_float_c<uint_X_t, false, true, true>; \
855 conv_function_chroma = convert_uintN_to_float_c<uint_X_t, true, true, true>; \
856 } \
857 else if (fulls && !fulld) { \
858 conv_function = convert_uintN_to_float_c<uint_X_t, false, true, false>; \
859 conv_function_chroma = convert_uintN_to_float_c<uint_X_t, true, true, false>; \
860 } \
861 else if (!fulls && fulld) { \
862 conv_function = convert_uintN_to_float_c<uint_X_t, false, false, true>; \
863 conv_function_chroma = convert_uintN_to_float_c<uint_X_t, true, false, true>; \
864 } \
865 else if (!fulls && !fulld) { \
866 conv_function = convert_uintN_to_float_c<uint_X_t, false, false, false>; \
867 conv_function_chroma = convert_uintN_to_float_c<uint_X_t, true, false, false>; \
868 }
869
870 #define convert_uintN_to_float_functions_avx2(uint_X_t) \
871 conv_function_a = convert_uintN_to_float_avx2<uint_X_t, false, true, true>; /* full-full */ \
872 if (fulls && fulld) { \
873 conv_function = convert_uintN_to_float_avx2<uint_X_t, false, true, true>; \
874 conv_function_chroma = convert_uintN_to_float_avx2<uint_X_t, true, true, true>; \
875 } \
876 else if (fulls && !fulld) { \
877 conv_function = convert_uintN_to_float_avx2<uint_X_t, false, true, false>; \
878 conv_function_chroma = convert_uintN_to_float_avx2<uint_X_t, true, true, false>; \
879 } \
880 else if (!fulls && fulld) { \
881 conv_function = convert_uintN_to_float_avx2<uint_X_t, false, false, true>; \
882 conv_function_chroma = convert_uintN_to_float_avx2<uint_X_t, true, false, true>; \
883 } \
884 else if (!fulls && !fulld) { \
885 conv_function = convert_uintN_to_float_avx2<uint_X_t, false, false, false>; \
886 conv_function_chroma = convert_uintN_to_float_avx2<uint_X_t, true, false, false>; \
887 }
888
889 switch (bits_per_pixel) {
890 case 8:
891 convert_uintN_to_float_functions(uint8_t);
892 break;
893 default: // 10-16 bits
894 convert_uintN_to_float_functions(uint16_t);
895 break;
896 }
897
898 #ifdef INTEL_INTRINSICS
899 if (avx2) {
900 switch (bits_per_pixel) {
901 case 8:
902 convert_uintN_to_float_functions_avx2(uint8_t);
903 break;
904 default: // 10-16 bits
905 convert_uintN_to_float_functions_avx2(uint16_t);
906 break;
907 }
908 }
909 #endif
910
911
912 #undef convert_uintN_to_float_functions
913 }
914
915 static void get_convert_uintN_to_uintN_ordered_dither_functions(int source_bitdepth, int target_bitdepth, bool fulls, bool fulld,
916 #ifdef INTEL_INTRINSICS
917 bool sse2, bool sse4, bool avx2,
918 #endif
919 BitDepthConvFuncPtr& conv_function, BitDepthConvFuncPtr& conv_function_chroma)
920 {
921 // 8-16->8-16 bits support any fulls fulld combination
922 // dither has no "conv_function_a"
923 // pure C
924 #define convert_uintN_to_uintN_ordered_dither_functions(uint_X_t, uint_X_dest_t) \
925 if (fulls && fulld) { \
926 conv_function = convert_ordered_dither_uint_c<uint_X_t, uint_X_dest_t, false, true, true>; \
927 conv_function_chroma = convert_ordered_dither_uint_c<uint_X_t, uint_X_dest_t, true, true, true>; \
928 } \
929 else if (fulls && !fulld) { \
930 conv_function = convert_ordered_dither_uint_c<uint_X_t, uint_X_dest_t, false, true, false>; \
931 conv_function_chroma = convert_ordered_dither_uint_c<uint_X_t, uint_X_dest_t, true, true, false>; \
932 } \
933 else if (!fulls && fulld) { \
934 conv_function = convert_ordered_dither_uint_c<uint_X_t, uint_X_dest_t, false, false, true>; \
935 conv_function_chroma = convert_ordered_dither_uint_c<uint_X_t, uint_X_dest_t, true, false, true>; \
936 } \
937 else if (!fulls && !fulld) { \
938 conv_function = convert_ordered_dither_uint_c<uint_X_t, uint_X_dest_t, false, false, false>; \
939 conv_function_chroma = convert_ordered_dither_uint_c<uint_X_t, uint_X_dest_t, true, false, false>; \
940 }
941
942 #ifdef INTEL_INTRINSICS
943 #undef convert_uintN_to_uintN_ordered_dither_functions
944 // dither has no "conv_function_a"
945 #define convert_uintN_to_uintN_ordered_dither_functions(uint_X_t, uint_X_dest_t) \
946 if (fulls && fulld) { \
947 conv_function = avx2 ? convert_ordered_dither_uint_avx2<uint_X_t, uint_X_dest_t, false, true, true> : sse4 ? convert_ordered_dither_uint_sse41<uint_X_t, uint_X_dest_t, false, true, true> : convert_ordered_dither_uint_c<uint_X_t, uint_X_dest_t, false, true, true>; \
948 conv_function_chroma = avx2 ? convert_ordered_dither_uint_avx2<uint_X_t, uint_X_dest_t, true, true, true> : sse4 ? convert_ordered_dither_uint_sse41<uint_X_t, uint_X_dest_t, true, true, true> : convert_ordered_dither_uint_c<uint_X_t, uint_X_dest_t, true, true, true>; \
949 } \
950 else if (fulls && !fulld) { \
951 conv_function = avx2 ? convert_ordered_dither_uint_avx2<uint_X_t, uint_X_dest_t, false, true, false> : sse4 ? convert_ordered_dither_uint_sse41<uint_X_t, uint_X_dest_t, false, true, false> : convert_ordered_dither_uint_c<uint_X_t, uint_X_dest_t, false, true, false>; \
952 conv_function_chroma = avx2 ? convert_ordered_dither_uint_avx2<uint_X_t, uint_X_dest_t, true, true, false> : sse4 ? convert_ordered_dither_uint_sse41<uint_X_t, uint_X_dest_t, true, true, false> : convert_ordered_dither_uint_c<uint_X_t, uint_X_dest_t, true, true, false>; \
953 } \
954 else if (!fulls && fulld) { \
955 conv_function = avx2 ? convert_ordered_dither_uint_avx2<uint_X_t, uint_X_dest_t, false, false, true> : sse4 ? convert_ordered_dither_uint_sse41<uint_X_t, uint_X_dest_t, false, false, true> : convert_ordered_dither_uint_c<uint_X_t, uint_X_dest_t, false, false, true>; \
956 conv_function_chroma = avx2 ? convert_ordered_dither_uint_avx2<uint_X_t, uint_X_dest_t, true, false, true> : sse4 ? convert_ordered_dither_uint_sse41<uint_X_t, uint_X_dest_t, true, false, true> : convert_ordered_dither_uint_c<uint_X_t, uint_X_dest_t, true, false, true>; \
957 } \
958 else if (!fulls && !fulld) { \
959 conv_function = avx2 ? convert_ordered_dither_uint_avx2<uint_X_t, uint_X_dest_t, false, false, false> : sse4 ? convert_ordered_dither_uint_sse41<uint_X_t, uint_X_dest_t, false, false, false> : convert_ordered_dither_uint_c<uint_X_t, uint_X_dest_t, false, false, false>; \
960 conv_function_chroma = avx2 ? convert_ordered_dither_uint_avx2<uint_X_t, uint_X_dest_t, true, false, false> : sse4 ? convert_ordered_dither_uint_sse41<uint_X_t, uint_X_dest_t, true, false, false> : convert_ordered_dither_uint_c<uint_X_t, uint_X_dest_t, true, false, false>; \
961 }
962 #endif
963 // all variations of fulls fulld byte/word source/target
964 switch (target_bitdepth)
965 {
966 case 8:
967 if (source_bitdepth == 8) {
968 convert_uintN_to_uintN_ordered_dither_functions(uint8_t, uint8_t);
969 }
970 else {
971 convert_uintN_to_uintN_ordered_dither_functions(uint16_t, uint8_t);
972 }
973 break;
974 default:
975 // uint16_t target is always uint16_t source
976 convert_uintN_to_uintN_ordered_dither_functions(uint16_t, uint16_t);
977 break;
978 }
979
980 #undef convert_uintN_to_uintN_ordered_dither_functions
981 }
982
983 static void get_convert_uintN_to_uintN_floyd_dither_functions(int source_bitdepth, int target_bitdepth, bool fulls, bool fulld,
984 BitDepthConvFuncPtr& conv_function, BitDepthConvFuncPtr& conv_function_chroma)
985 {
986 // 8-16->8-16 bits support any fulls fulld combination
987 // dither has no "conv_function_a"
988 // pure C
989 #define convert_uintN_to_uintN_floyd_dither_functions(uint_X_t, uint_X_dest_t) \
990 if (fulls && fulld) { \
991 conv_function = convert_uint_floyd_c<uint_X_t, uint_X_dest_t, false, true, true>; \
992 conv_function_chroma = convert_uint_floyd_c<uint_X_t, uint_X_dest_t, true, true, true>; \
993 } \
994 else if (fulls && !fulld) { \
995 conv_function = convert_uint_floyd_c<uint_X_t, uint_X_dest_t, false, true, false>; \
996 conv_function_chroma = convert_uint_floyd_c<uint_X_t, uint_X_dest_t, true, true, false>; \
997 } \
998 else if (!fulls && fulld) { \
999 conv_function = convert_uint_floyd_c<uint_X_t, uint_X_dest_t, false, false, true>; \
1000 conv_function_chroma = convert_uint_floyd_c<uint_X_t, uint_X_dest_t, true, false, true>; \
1001 } \
1002 else if (!fulls && !fulld) { \
1003 conv_function = convert_uint_floyd_c<uint_X_t, uint_X_dest_t, false, false, false>; \
1004 conv_function_chroma = convert_uint_floyd_c<uint_X_t, uint_X_dest_t, true, false, false>; \
1005 }
1006
1007 // all variations of fulls fulld byte/word source/target
1008 switch (target_bitdepth)
1009 {
1010 case 8:
1011 if (source_bitdepth == 8) {
1012 convert_uintN_to_uintN_floyd_dither_functions(uint8_t, uint8_t);
1013 }
1014 else {
1015 convert_uintN_to_uintN_floyd_dither_functions(uint16_t, uint8_t);
1016 }
1017 break;
1018 default:
1019 // uint16_t target is always uint16_t source
1020 convert_uintN_to_uintN_floyd_dither_functions(uint16_t, uint16_t);
1021 break;
1022 }
1023
1024 #undef convert_uintN_to_uintN_floyd_dither_functions
1025 }
1026
1027
1028 8 static void get_convert_uintN_to_uintN_functions(int source_bitdepth, int target_bitdepth, bool fulls, bool fulld,
1029 #ifdef INTEL_INTRINSICS
1030 bool sse2, bool sse4, bool avx2,
1031 #endif
1032 BitDepthConvFuncPtr& conv_function, BitDepthConvFuncPtr& conv_function_chroma, BitDepthConvFuncPtr& conv_function_a)
1033 {
1034 // 8-16->8-16 bits support any fulls fulld combination
1035 // pure C
1036 #define convert_uintN_to_uintN_functions(uint_X_t, uint_X_dest_t) \
1037 conv_function_a = convert_uint_c<uint_X_t, uint_X_dest_t, false, true, true>; /* full-full */ \
1038 if (fulls && fulld) { \
1039 conv_function = convert_uint_c<uint_X_t, uint_X_dest_t, false, true, true>; \
1040 conv_function_chroma = convert_uint_c<uint_X_t, uint_X_dest_t, true, true, true>; \
1041 } \
1042 else if (fulls && !fulld) { \
1043 conv_function = convert_uint_c<uint_X_t, uint_X_dest_t, false, true, false>; \
1044 conv_function_chroma = convert_uint_c<uint_X_t, uint_X_dest_t, true, true, false>; \
1045 } \
1046 else if (!fulls && fulld) { \
1047 conv_function = convert_uint_c<uint_X_t, uint_X_dest_t, false, false, true>; \
1048 conv_function_chroma = convert_uint_c<uint_X_t, uint_X_dest_t, true, false, true>; \
1049 } \
1050 else if (!fulls && !fulld) { \
1051 conv_function = convert_uint_c<uint_X_t, uint_X_dest_t, false, false, false>; \
1052 conv_function_chroma = convert_uint_c<uint_X_t, uint_X_dest_t, true, false, false>; \
1053 }
1054
1055 #ifdef INTEL_INTRINSICS
1056 #undef convert_uintN_to_uintN_functions
1057
1058 #define convert_uintN_to_uintN_functions(uint_X_t, uint_X_dest_t) \
1059 conv_function_a = avx2 ? convert_uint_avx2<uint_X_t, uint_X_dest_t, false, true, true> : sse4 ? convert_uint_sse41<uint_X_t, uint_X_dest_t, false, true, true> : convert_uint_c<uint_X_t, uint_X_dest_t, false, true, true>; /* full-full */ \
1060 if (fulls && fulld) { \
1061 conv_function = avx2 ? convert_uint_avx2<uint_X_t, uint_X_dest_t, false, true, true> : sse4 ? convert_uint_sse41<uint_X_t, uint_X_dest_t, false, true, true> : convert_uint_c<uint_X_t, uint_X_dest_t, false, true, true>; \
1062 conv_function_chroma = avx2 ? convert_uint_avx2<uint_X_t, uint_X_dest_t, true, true, true> : sse4 ? convert_uint_sse41<uint_X_t, uint_X_dest_t, true, true, true> : convert_uint_c<uint_X_t, uint_X_dest_t, true, true, true>; \
1063 } \
1064 else if (fulls && !fulld) { \
1065 conv_function = avx2 ? convert_uint_avx2<uint_X_t, uint_X_dest_t, false, true, false> : sse4 ? convert_uint_sse41<uint_X_t, uint_X_dest_t, false, true, false> : convert_uint_c<uint_X_t, uint_X_dest_t, false, true, false>; \
1066 conv_function_chroma = avx2 ? convert_uint_avx2<uint_X_t, uint_X_dest_t, true, true, false> : sse4 ? convert_uint_sse41<uint_X_t, uint_X_dest_t, true, true, false> : convert_uint_c<uint_X_t, uint_X_dest_t, true, true, false>; \
1067 } \
1068 else if (!fulls && fulld) { \
1069 conv_function = avx2 ? convert_uint_avx2<uint_X_t, uint_X_dest_t, false, false, true> : sse4 ? convert_uint_sse41<uint_X_t, uint_X_dest_t, false, false, true> : convert_uint_c<uint_X_t, uint_X_dest_t, false, false, true>; \
1070 conv_function_chroma = avx2 ? convert_uint_avx2<uint_X_t, uint_X_dest_t, true, false, true> : sse4 ? convert_uint_sse41<uint_X_t, uint_X_dest_t, true, false, true> : convert_uint_c<uint_X_t, uint_X_dest_t, true, false, true>; \
1071 } \
1072 else if (!fulls && !fulld) { \
1073 conv_function = avx2 ? convert_uint_avx2<uint_X_t, uint_X_dest_t, false, false, false> : sse4 ? convert_uint_sse41<uint_X_t, uint_X_dest_t, false, false, false> : convert_uint_c<uint_X_t, uint_X_dest_t, false, false, false>; \
1074 conv_function_chroma = avx2 ? convert_uint_avx2<uint_X_t, uint_X_dest_t, true, false, false> : sse4 ? convert_uint_sse41<uint_X_t, uint_X_dest_t, true, false, false> : convert_uint_c<uint_X_t, uint_X_dest_t, true, false, false>; \
1075 }
1076 #endif
1077
1078 // all variations of fulls fulld byte/word source/target
1079
2/2
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 120 taken 7 times.
8 switch (target_bitdepth)
1080 {
1081 1 case 8:
1082
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 62 taken 1 time.
1 if (source_bitdepth == 8) {
1083 convert_uintN_to_uintN_functions(uint8_t, uint8_t);
1084 }
1085 else {
1086
5/52
✓ Branch 62 → 63 taken 1 time.
✗ Branch 62 → 64 not taken.
✗ Branch 64 → 65 not taken.
✗ Branch 64 → 66 not taken.
✓ Branch 67 → 68 taken 1 time.
✗ Branch 67 → 80 not taken.
✓ Branch 68 → 69 taken 1 time.
✗ Branch 68 → 80 not taken.
✓ Branch 69 → 70 taken 1 time.
✗ Branch 69 → 71 not taken.
✗ Branch 71 → 72 not taken.
✗ Branch 71 → 73 not taken.
✓ Branch 74 → 75 taken 1 time.
✗ Branch 74 → 76 not taken.
✗ Branch 76 → 77 not taken.
✗ Branch 76 → 78 not taken.
✗ Branch 80 → 81 not taken.
✗ Branch 80 → 93 not taken.
✗ Branch 81 → 82 not taken.
✗ Branch 81 → 93 not taken.
✗ Branch 82 → 83 not taken.
✗ Branch 82 → 84 not taken.
✗ Branch 84 → 85 not taken.
✗ Branch 84 → 86 not taken.
✗ Branch 87 → 88 not taken.
✗ Branch 87 → 89 not taken.
✗ Branch 89 → 90 not taken.
✗ Branch 89 → 91 not taken.
✗ Branch 93 → 94 not taken.
✗ Branch 93 → 106 not taken.
✗ Branch 94 → 95 not taken.
✗ Branch 94 → 106 not taken.
✗ Branch 95 → 96 not taken.
✗ Branch 95 → 97 not taken.
✗ Branch 97 → 98 not taken.
✗ Branch 97 → 99 not taken.
✗ Branch 100 → 101 not taken.
✗ Branch 100 → 102 not taken.
✗ Branch 102 → 103 not taken.
✗ Branch 102 → 104 not taken.
✗ Branch 106 → 107 not taken.
✗ Branch 106 → 119 not taken.
✗ Branch 107 → 108 not taken.
✗ Branch 107 → 119 not taken.
✗ Branch 108 → 109 not taken.
✗ Branch 108 → 110 not taken.
✗ Branch 110 → 111 not taken.
✗ Branch 110 → 112 not taken.
✗ Branch 113 → 114 not taken.
✗ Branch 113 → 115 not taken.
✗ Branch 115 → 116 not taken.
✗ Branch 115 → 117 not taken.
1 convert_uintN_to_uintN_functions(uint16_t, uint8_t);
1087 }
1088 1 break;
1089 7 default:
1090 // 10-16 bits
1091
2/2
✓ Branch 120 → 121 taken 6 times.
✓ Branch 120 → 179 taken 1 time.
7 if (source_bitdepth == 8)
1092 {
1093
18/52
✓ Branch 121 → 122 taken 6 times.
✗ Branch 121 → 123 not taken.
✗ Branch 123 → 124 not taken.
✗ Branch 123 → 125 not taken.
✓ Branch 126 → 127 taken 5 times.
✓ Branch 126 → 139 taken 1 time.
✓ Branch 127 → 128 taken 4 times.
✓ Branch 127 → 139 taken 1 time.
✓ Branch 128 → 129 taken 4 times.
✗ Branch 128 → 130 not taken.
✗ Branch 130 → 131 not taken.
✗ Branch 130 → 132 not taken.
✓ Branch 133 → 134 taken 4 times.
✗ Branch 133 → 135 not taken.
✗ Branch 135 → 136 not taken.
✗ Branch 135 → 137 not taken.
✓ Branch 139 → 140 taken 1 time.
✓ Branch 139 → 152 taken 1 time.
✓ Branch 140 → 141 taken 1 time.
✗ Branch 140 → 152 not taken.
✓ Branch 141 → 142 taken 1 time.
✗ Branch 141 → 143 not taken.
✗ Branch 143 → 144 not taken.
✗ Branch 143 → 145 not taken.
✓ Branch 146 → 147 taken 1 time.
✗ Branch 146 → 148 not taken.
✗ Branch 148 → 149 not taken.
✗ Branch 148 → 150 not taken.
✓ Branch 152 → 153 taken 1 time.
✗ Branch 152 → 165 not taken.
✗ Branch 153 → 154 not taken.
✓ Branch 153 → 165 taken 1 time.
✗ Branch 154 → 155 not taken.
✗ Branch 154 → 156 not taken.
✗ Branch 156 → 157 not taken.
✗ Branch 156 → 158 not taken.
✗ Branch 159 → 160 not taken.
✗ Branch 159 → 161 not taken.
✗ Branch 161 → 162 not taken.
✗ Branch 161 → 163 not taken.
✓ Branch 165 → 166 taken 1 time.
✗ Branch 165 → 178 not taken.
✓ Branch 166 → 167 taken 1 time.
✗ Branch 166 → 178 not taken.
✓ Branch 167 → 168 taken 1 time.
✗ Branch 167 → 169 not taken.
✗ Branch 169 → 170 not taken.
✗ Branch 169 → 171 not taken.
✓ Branch 172 → 173 taken 1 time.
✗ Branch 172 → 174 not taken.
✗ Branch 174 → 175 not taken.
✗ Branch 174 → 176 not taken.
6 convert_uintN_to_uintN_functions(uint8_t, uint16_t);
1094 }
1095 else {
1096
5/52
✓ Branch 179 → 180 taken 1 time.
✗ Branch 179 → 181 not taken.
✗ Branch 181 → 182 not taken.
✗ Branch 181 → 183 not taken.
✓ Branch 184 → 185 taken 1 time.
✗ Branch 184 → 197 not taken.
✓ Branch 185 → 186 taken 1 time.
✗ Branch 185 → 197 not taken.
✓ Branch 186 → 187 taken 1 time.
✗ Branch 186 → 188 not taken.
✗ Branch 188 → 189 not taken.
✗ Branch 188 → 190 not taken.
✓ Branch 191 → 192 taken 1 time.
✗ Branch 191 → 193 not taken.
✗ Branch 193 → 194 not taken.
✗ Branch 193 → 195 not taken.
✗ Branch 197 → 198 not taken.
✗ Branch 197 → 210 not taken.
✗ Branch 198 → 199 not taken.
✗ Branch 198 → 210 not taken.
✗ Branch 199 → 200 not taken.
✗ Branch 199 → 201 not taken.
✗ Branch 201 → 202 not taken.
✗ Branch 201 → 203 not taken.
✗ Branch 204 → 205 not taken.
✗ Branch 204 → 206 not taken.
✗ Branch 206 → 207 not taken.
✗ Branch 206 → 208 not taken.
✗ Branch 210 → 211 not taken.
✗ Branch 210 → 223 not taken.
✗ Branch 211 → 212 not taken.
✗ Branch 211 → 223 not taken.
✗ Branch 212 → 213 not taken.
✗ Branch 212 → 214 not taken.
✗ Branch 214 → 215 not taken.
✗ Branch 214 → 216 not taken.
✗ Branch 217 → 218 not taken.
✗ Branch 217 → 219 not taken.
✗ Branch 219 → 220 not taken.
✗ Branch 219 → 221 not taken.
✗ Branch 223 → 224 not taken.
✗ Branch 223 → 236 not taken.
✗ Branch 224 → 225 not taken.
✗ Branch 224 → 236 not taken.
✗ Branch 225 → 226 not taken.
✗ Branch 225 → 227 not taken.
✗ Branch 227 → 228 not taken.
✗ Branch 227 → 229 not taken.
✗ Branch 230 → 231 not taken.
✗ Branch 230 → 232 not taken.
✗ Branch 232 → 233 not taken.
✗ Branch 232 → 234 not taken.
1 convert_uintN_to_uintN_functions(uint16_t, uint16_t);
1097 }
1098 7 break;
1099 }
1100
1101 #undef convert_uintN_to_uintN_functions
1102 8 }
1103
1104 8 void get_convert_any_bits_functions(int dither_mode, int source_bitdepth, int target_bitdepth, bool fulls, bool fulld,
1105 #ifdef INTEL_INTRINSICS
1106 bool sse2, bool sse4, bool avx2,
1107 #endif
1108 BitDepthConvFuncPtr& conv_function, BitDepthConvFuncPtr& conv_function_chroma, BitDepthConvFuncPtr& conv_function_a)
1109 {
1110
1111
2/4
✓ Branch 2 → 3 taken 8 times.
✗ Branch 2 → 10 not taken.
✓ Branch 3 → 4 taken 8 times.
✗ Branch 3 → 10 not taken.
8 if (source_bitdepth <= 16 && target_bitdepth <= 16)
1112 {
1113 // get basic non-dithered versions
1114 #ifdef INTEL_INTRINSICS
1115 8 get_convert_uintN_to_uintN_functions(source_bitdepth, target_bitdepth, fulls, fulld, sse2, sse4, avx2, conv_function, conv_function_chroma, conv_function_a);
1116 #else
1117 get_convert_uintN_to_uintN_functions(source_bitdepth, target_bitdepth, fulls, fulld, conv_function, conv_function_chroma, conv_function_a);
1118 #endif
1119
2/2
✓ Branch 5 → 6 taken 2 times.
✓ Branch 5 → 10 taken 6 times.
8 if (target_bitdepth <= source_bitdepth) {
1120 // dither is only down
1121
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 2 times.
2 if (dither_mode == 0) {
1122 // ordered dither
1123 #ifdef INTEL_INTRINSICS
1124 get_convert_uintN_to_uintN_ordered_dither_functions(source_bitdepth, target_bitdepth, fulls, fulld, sse2, sse4, avx2, conv_function, conv_function_chroma);
1125 #else
1126 get_convert_uintN_to_uintN_ordered_dither_functions(source_bitdepth, target_bitdepth, fulls, fulld, conv_function, conv_function_chroma);
1127 #endif
1128 }
1129
1/2
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 2 times.
2 else if (dither_mode == 1) {
1130 // Floyd, no SIMD there
1131 get_convert_uintN_to_uintN_floyd_dither_functions(source_bitdepth, target_bitdepth, fulls, fulld, conv_function, conv_function_chroma);
1132 }
1133 }
1134 }
1135
1136 // 32->8-16 bit
1137
1/4
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 13 taken 8 times.
✗ Branch 11 → 12 not taken.
✗ Branch 11 → 13 not taken.
8 if (source_bitdepth == 32 && target_bitdepth <= 16) {
1138 #ifdef INTEL_INTRINSICS
1139 get_convert_32_to_uintN_functions(target_bitdepth, fulls, fulld, sse2, sse4, avx2, conv_function, conv_function_chroma, conv_function_a);
1140 #else
1141 get_convert_32_to_uintN_functions(target_bitdepth, fulls, fulld, conv_function, conv_function_chroma, conv_function_a);
1142 #endif
1143 }
1144
1145 // 8-32->32
1146
1/2
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 17 taken 8 times.
8 if (target_bitdepth == 32) {
1147 if (source_bitdepth <= 16) // 8-16->32 bit
1148 #ifdef INTEL_INTRINSICS
1149 get_convert_uintN_to_float_functions(source_bitdepth, fulls, fulld, sse2, sse4, avx2, conv_function, conv_function_chroma, conv_function_a);
1150 #else
1151 get_convert_uintN_to_float_functions(source_bitdepth, fulls, fulld, conv_function, conv_function_chroma, conv_function_a);
1152 #endif
1153 else
1154 get_convert_float_to_float_functions(fulls, fulld, conv_function, conv_function_chroma, conv_function_a);
1155 }
1156 8 }
1157
1158
1159 4 ConvertBits::ConvertBits(PClip _child, const int _dither_mode, const int _target_bitdepth, bool _truerange,
1160 int _ColorRange_src, int _ColorRange_dest,
1161 4 int _dither_bitdepth, IScriptEnvironment* env) :
1162 GenericVideoFilter(_child),
1163 4 conv_function(nullptr), conv_function_chroma(nullptr), conv_function_a(nullptr),
1164 4 target_bitdepth(_target_bitdepth), dither_mode(_dither_mode), dither_bitdepth(_dither_bitdepth),
1165
2/4
✓ Branch 2 → 3 taken 4 times.
✗ Branch 2 → 153 not taken.
✓ Branch 3 → 4 taken 4 times.
✗ Branch 3 → 151 not taken.
4 fulls(false), fulld(false), truerange(_truerange)
1166 {
1167
1168
1/2
✓ Branch 5 → 6 taken 4 times.
✗ Branch 5 → 154 not taken.
4 pixelsize = vi.ComponentSize();
1169
1/2
✓ Branch 6 → 7 taken 4 times.
✗ Branch 6 → 154 not taken.
4 bits_per_pixel = vi.BitsPerComponent();
1170 4 format_change_only = false;
1171
1172 #ifdef INTEL_INTRINSICS
1173
1/2
✓ Branch 7 → 8 taken 4 times.
✗ Branch 7 → 154 not taken.
4 const bool sse2 = !!(env->GetCPUFlags() & CPUF_SSE2);
1174
1/2
✓ Branch 8 → 9 taken 4 times.
✗ Branch 8 → 154 not taken.
4 const bool sse4 = !!(env->GetCPUFlags() & CPUF_SSE4_1);
1175
1/2
✓ Branch 9 → 10 taken 4 times.
✗ Branch 9 → 154 not taken.
4 const bool avx2 = !!(env->GetCPUFlags() & CPUF_AVX2);
1176 #endif
1177
1178 // full or limited decision
1179 // dest: if undefined, use src
1180
3/4
✓ Branch 10 → 11 taken 2 times.
✓ Branch 10 → 13 taken 2 times.
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 2 times.
4 if (_ColorRange_dest != ColorRange_Compat_e::AVS_COLORRANGE_LIMITED && _ColorRange_dest != ColorRange_Compat_e::AVS_COLORRANGE_FULL) {
1181 _ColorRange_dest = _ColorRange_src;
1182 }
1183 //
1184 4 fulls = _ColorRange_src == ColorRange_Compat_e::AVS_COLORRANGE_FULL;
1185 4 fulld = _ColorRange_dest == ColorRange_Compat_e::AVS_COLORRANGE_FULL;
1186
1187
1/2
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 28 taken 4 times.
4 if (!truerange) {
1188 if ((target_bitdepth == 8 || target_bitdepth == 32) && pixelsize == 2)
1189 bits_per_pixel = 16;
1190 if (target_bitdepth > 8 && target_bitdepth <= 16 && (bits_per_pixel == 8 || bits_per_pixel == 32))
1191 target_bitdepth = 16;
1192 if (target_bitdepth > 8 && target_bitdepth <= 16 && bits_per_pixel > 8 && bits_per_pixel <= 16)
1193 format_change_only = true;
1194 }
1195
1196 #ifdef INTEL_INTRINSICS
1197 4 get_convert_any_bits_functions(dither_mode, bits_per_pixel, target_bitdepth, fulls, fulld, sse2, sse4, avx2, conv_function, conv_function_chroma, conv_function_a);
1198 #else
1199 get_convert_any_bits_functions(dither_mode, bits_per_pixel, target_bitdepth, fulls, fulld, conv_function, conv_function_chroma, conv_function_a);
1200 #endif
1201
1202 // Set VideoInfo
1203
2/2
✓ Branch 29 → 30 taken 1 time.
✓ Branch 29 → 86 taken 3 times.
4 if (target_bitdepth == 8) {
1204
2/4
✓ Branch 30 → 31 taken 1 time.
✗ Branch 30 → 154 not taken.
✓ Branch 31 → 32 taken 1 time.
✗ Branch 31 → 33 not taken.
1 if (vi.NumComponents() == 1)
1205 1 vi.pixel_type = VideoInfo::CS_Y8;
1206 else if (vi.IsYV411())
1207 vi.pixel_type = VideoInfo::CS_YV411;
1208 else if (vi.Is420() || vi.IsYV12())
1209 vi.pixel_type = vi.IsYUVA() ? VideoInfo::CS_YUVA420 : VideoInfo::CS_YV12;
1210 else if (vi.Is422())
1211 vi.pixel_type = vi.IsYUVA() ? VideoInfo::CS_YUVA422 : VideoInfo::CS_YV16;
1212 else if (vi.Is444())
1213 vi.pixel_type = vi.IsYUVA() ? VideoInfo::CS_YUVA444 : VideoInfo::CS_YV24;
1214 else if (vi.IsRGB48() || vi.IsRGB24())
1215 vi.pixel_type = VideoInfo::CS_BGR24;
1216 else if (vi.IsRGB64() || vi.IsRGB32())
1217 vi.pixel_type = VideoInfo::CS_BGR32;
1218 else if (vi.IsPlanarRGB())
1219 vi.pixel_type = VideoInfo::CS_RGBP;
1220 else if (vi.IsPlanarRGBA())
1221 vi.pixel_type = VideoInfo::CS_RGBAP;
1222 else
1223 env->ThrowError("ConvertTo8bit: unsupported color space");
1224
1225 1 return;
1226 }
1227
2/4
✓ Branch 86 → 87 taken 3 times.
✗ Branch 86 → 116 not taken.
✓ Branch 87 → 88 taken 3 times.
✗ Branch 87 → 116 not taken.
3 else if (target_bitdepth > 8 && target_bitdepth <= 16) {
1228 // set output vi format
1229
5/10
✓ Branch 88 → 89 taken 3 times.
✗ Branch 88 → 154 not taken.
✓ Branch 89 → 90 taken 3 times.
✗ Branch 89 → 92 not taken.
✓ Branch 90 → 91 taken 3 times.
✗ Branch 90 → 154 not taken.
✗ Branch 91 → 92 not taken.
✓ Branch 91 → 93 taken 3 times.
✗ Branch 94 → 95 not taken.
✓ Branch 94 → 96 taken 3 times.
3 if (vi.IsRGB24() || vi.IsRGB48()) {
1230 vi.pixel_type = VideoInfo::CS_BGR48;
1231 }
1232
5/10
✓ Branch 96 → 97 taken 3 times.
✗ Branch 96 → 154 not taken.
✓ Branch 97 → 98 taken 3 times.
✗ Branch 97 → 100 not taken.
✓ Branch 98 → 99 taken 3 times.
✗ Branch 98 → 154 not taken.
✗ Branch 99 → 100 not taken.
✓ Branch 99 → 101 taken 3 times.
✗ Branch 102 → 103 not taken.
✓ Branch 102 → 104 taken 3 times.
3 else if (vi.IsRGB32() || vi.IsRGB64()) {
1233 vi.pixel_type = VideoInfo::CS_BGR64;
1234 }
1235 else {
1236 // Y or YUV(A) or PlanarRGB(A)
1237
2/4
✓ Branch 104 → 105 taken 3 times.
✗ Branch 104 → 154 not taken.
✗ Branch 105 → 106 not taken.
✓ Branch 105 → 107 taken 3 times.
3 if (vi.IsYV12()) // YV12 can have an exotic compatibility constant
1238 vi.pixel_type = VideoInfo::CS_YV12; // override for known
1239 int new_bitdepth_bits;
1240
2/7
✗ Branch 107 → 108 not taken.
✓ Branch 107 → 109 taken 2 times.
✗ Branch 107 → 110 not taken.
✗ Branch 107 → 111 not taken.
✓ Branch 107 → 112 taken 1 time.
✗ Branch 107 → 113 not taken.
✗ Branch 107 → 114 not taken.
3 switch (target_bitdepth) {
1241 case 8: new_bitdepth_bits = VideoInfo::CS_Sample_Bits_8; break;
1242 2 case 10: new_bitdepth_bits = VideoInfo::CS_Sample_Bits_10; break;
1243 case 12: new_bitdepth_bits = VideoInfo::CS_Sample_Bits_12; break;
1244 case 14: new_bitdepth_bits = VideoInfo::CS_Sample_Bits_14; break;
1245 1 case 16: new_bitdepth_bits = VideoInfo::CS_Sample_Bits_16; break;
1246 case 32: new_bitdepth_bits = VideoInfo::CS_Sample_Bits_32; break;
1247 }
1248 3 vi.pixel_type = (vi.pixel_type & ~VideoInfo::CS_Sample_Bits_Mask) | new_bitdepth_bits;
1249 }
1250 3 return;
1251 }
1252 else if (target_bitdepth == 32) {
1253 if (vi.NumComponents() == 1)
1254 vi.pixel_type = VideoInfo::CS_Y32;
1255 else if (vi.Is420())
1256 vi.pixel_type = vi.IsYUVA() ? VideoInfo::CS_YUVA420PS : VideoInfo::CS_YUV420PS;
1257 else if (vi.Is422())
1258 vi.pixel_type = vi.IsYUVA() ? VideoInfo::CS_YUVA422PS : VideoInfo::CS_YUV422PS;
1259 else if (vi.Is444())
1260 vi.pixel_type = vi.IsYUVA() ? VideoInfo::CS_YUVA444PS : VideoInfo::CS_YUV444PS;
1261 else if (vi.IsPlanarRGB())
1262 vi.pixel_type = VideoInfo::CS_RGBPS;
1263 else if (vi.IsPlanarRGBA())
1264 vi.pixel_type = VideoInfo::CS_RGBAPS;
1265 else
1266 env->ThrowError("ConvertToFloat: unsupported color space");
1267
1268 return;
1269 }
1270
1271 env->ThrowError("ConvertBits: unsupported target bit-depth (%d)", target_bitdepth);
1272
1273 }
1274
1275 4 AVSValue __cdecl ConvertBits::Create(AVSValue args, void* user_data, IScriptEnvironment* env) {
1276
2/4
✓ Branch 2 → 3 taken 4 times.
✗ Branch 2 → 599 not taken.
✓ Branch 3 → 4 taken 4 times.
✗ Branch 3 → 599 not taken.
4 PClip clip = args[0].AsClip();
1277 //0 1 2 3 4 5 6
1278 //c[bits]i[truerange]b[dither]i[dither_bits]i[fulls]b[fulld]b
1279
1280
1/2
✓ Branch 5 → 6 taken 4 times.
✗ Branch 5 → 597 not taken.
4 const VideoInfo &vi = clip->GetVideoInfo();
1281
1282 4 int create_param = (int)reinterpret_cast<intptr_t>(user_data);
1283
1284 // when converting from/true 10-16 bit formats, truerange=false indicates bitdepth of 16 bits regardless of the 10-12-14 bit format
1285 // FIXME: stop supporting this parameter (a workaround in the dawn of hbd?)
1286
2/4
✓ Branch 6 → 7 taken 4 times.
✗ Branch 6 → 597 not taken.
✓ Branch 7 → 8 taken 4 times.
✗ Branch 7 → 597 not taken.
4 bool assume_truerange = args[2].AsBool(true); // n/a for non planar formats
1287
1288
1/2
✓ Branch 8 → 9 taken 4 times.
✗ Branch 8 → 597 not taken.
4 int source_bitdepth = vi.BitsPerComponent();
1289 // default comes from old legacy To8,To16,ToFloat functions
1290 // or the clip's actual bit depth
1291
1/2
✓ Branch 9 → 10 taken 4 times.
✗ Branch 9 → 11 not taken.
4 const int default_target_bitdepth = create_param == 0 ? source_bitdepth : create_param;
1292
2/4
✓ Branch 12 → 13 taken 4 times.
✗ Branch 12 → 597 not taken.
✓ Branch 13 → 14 taken 4 times.
✗ Branch 13 → 597 not taken.
4 int target_bitdepth = args[1].AsInt(default_target_bitdepth); // "bits" parameter
1293
2/4
✓ Branch 14 → 15 taken 4 times.
✗ Branch 14 → 597 not taken.
✓ Branch 15 → 16 taken 4 times.
✗ Branch 15 → 597 not taken.
4 int dither_bitdepth = args[4].AsInt(target_bitdepth); // "dither_bits" parameter
1294
1295
7/12
✓ Branch 16 → 17 taken 3 times.
✓ Branch 16 → 23 taken 1 time.
✓ Branch 17 → 18 taken 1 time.
✓ Branch 17 → 23 taken 2 times.
✓ Branch 18 → 19 taken 1 time.
✗ Branch 18 → 23 not taken.
✓ Branch 19 → 20 taken 1 time.
✗ Branch 19 → 23 not taken.
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 23 taken 1 time.
✗ Branch 21 → 22 not taken.
✗ Branch 21 → 23 not taken.
4 if(target_bitdepth!=8 && target_bitdepth!=10 && target_bitdepth!=12 && target_bitdepth!=14 && target_bitdepth!=16 && target_bitdepth!=32)
1296 env->ThrowError("ConvertBits: invalid bit depth: %d", target_bitdepth);
1297
1298
1/4
✗ Branch 23 → 24 not taken.
✓ Branch 23 → 26 taken 4 times.
✗ Branch 24 → 25 not taken.
✗ Branch 24 → 26 not taken.
4 if(create_param == 8 && target_bitdepth !=8)
1299 env->ThrowError("ConvertTo8Bit: invalid bit depth: %d", target_bitdepth);
1300
1/4
✗ Branch 26 → 27 not taken.
✓ Branch 26 → 29 taken 4 times.
✗ Branch 27 → 28 not taken.
✗ Branch 27 → 29 not taken.
4 if(create_param == 32 && target_bitdepth !=32)
1301 env->ThrowError("ConvertToFloat: invalid bit depth: %d", target_bitdepth);
1302
1/6
✗ Branch 29 → 30 not taken.
✓ Branch 29 → 33 taken 4 times.
✗ Branch 30 → 31 not taken.
✗ Branch 30 → 32 not taken.
✗ Branch 31 → 32 not taken.
✗ Branch 31 → 33 not taken.
4 if(create_param == 16 && (target_bitdepth == 8 || target_bitdepth ==32))
1303 env->ThrowError("ConvertTo16bit: invalid bit depth: %d", target_bitdepth);
1304
1305
3/6
✓ Branch 33 → 34 taken 4 times.
✗ Branch 33 → 597 not taken.
✓ Branch 34 → 35 taken 4 times.
✗ Branch 34 → 597 not taken.
✓ Branch 35 → 36 taken 4 times.
✗ Branch 35 → 39 not taken.
4 if (args[2].Defined()) {
1306
2/4
✓ Branch 36 → 37 taken 4 times.
✗ Branch 36 → 597 not taken.
✗ Branch 37 → 38 not taken.
✓ Branch 37 → 39 taken 4 times.
4 if (!vi.IsPlanar())
1307 env->ThrowError("ConvertBits: truerange specified for non-planar source");
1308 }
1309
1310 // retrieve full/limited
1311 int ColorRange_src;
1312 int ColorRange_dest;
1313
4/6
✓ Branch 39 → 40 taken 4 times.
✗ Branch 39 → 597 not taken.
✓ Branch 40 → 41 taken 4 times.
✗ Branch 40 → 597 not taken.
✓ Branch 41 → 42 taken 2 times.
✓ Branch 41 → 47 taken 2 times.
4 if (args[5].Defined())
1314
3/6
✓ Branch 42 → 43 taken 2 times.
✗ Branch 42 → 597 not taken.
✓ Branch 43 → 44 taken 2 times.
✗ Branch 43 → 597 not taken.
✓ Branch 44 → 45 taken 2 times.
✗ Branch 44 → 46 not taken.
2 ColorRange_src = args[5].AsBool() ? ColorRange_Compat_e::AVS_COLORRANGE_FULL : ColorRange_Compat_e::AVS_COLORRANGE_LIMITED;
1315 else
1316 2 ColorRange_src = -1; // undefined. A frame property may override
1317
3/6
✓ Branch 48 → 49 taken 4 times.
✗ Branch 48 → 597 not taken.
✓ Branch 49 → 50 taken 4 times.
✗ Branch 49 → 597 not taken.
✓ Branch 50 → 51 taken 4 times.
✗ Branch 50 → 56 not taken.
4 if (args[6].Defined())
1318
4/6
✓ Branch 51 → 52 taken 4 times.
✗ Branch 51 → 597 not taken.
✓ Branch 52 → 53 taken 4 times.
✗ Branch 52 → 597 not taken.
✓ Branch 53 → 54 taken 2 times.
✓ Branch 53 → 55 taken 2 times.
4 ColorRange_dest = args[6].AsBool() ? ColorRange_Compat_e::AVS_COLORRANGE_FULL : ColorRange_Compat_e::AVS_COLORRANGE_LIMITED;
1319 else
1320 ColorRange_dest = -1; // undefined. A frame property or ColorRange_src may override
1321
3/4
✓ Branch 57 → 58 taken 4 times.
✗ Branch 57 → 72 not taken.
✓ Branch 58 → 59 taken 2 times.
✓ Branch 58 → 72 taken 2 times.
4 if (ColorRange_src != ColorRange_Compat_e::AVS_COLORRANGE_LIMITED && ColorRange_src != ColorRange_Compat_e::AVS_COLORRANGE_FULL) {
1322 // try getting frame props if parameter is not specified
1323
1/2
✓ Branch 60 → 61 taken 2 times.
✗ Branch 60 → 361 not taken.
2 auto frame0 = clip->GetFrame(0, env);
1324
1/2
✓ Branch 61 → 62 taken 2 times.
✗ Branch 61 → 359 not taken.
2 const AVSMap* props = env->getFramePropsRO(frame0);
1325
2/4
✓ Branch 62 → 63 taken 2 times.
✗ Branch 62 → 359 not taken.
✓ Branch 63 → 64 taken 2 times.
✗ Branch 63 → 66 not taken.
2 if (env->propNumElements(props, "_ColorRange") > 0) {
1326
1/2
✓ Branch 64 → 65 taken 2 times.
✗ Branch 64 → 359 not taken.
2 ColorRange_src = (int)env->propGetIntSaturated(props, "_ColorRange", 0, nullptr);
1327 }
1328 else {
1329 // no param, no frame property -> rgb is full others are limited
1330 ColorRange_src = vi.IsRGB() ? ColorRange_Compat_e::AVS_COLORRANGE_FULL : ColorRange_Compat_e::AVS_COLORRANGE_LIMITED;
1331 }
1332 2 }
1333 // cr_dest = cr_source if not specified
1334
3/4
✓ Branch 72 → 73 taken 2 times.
✓ Branch 72 → 75 taken 2 times.
✗ Branch 73 → 74 not taken.
✓ Branch 73 → 75 taken 2 times.
4 if (ColorRange_dest != ColorRange_Compat_e::AVS_COLORRANGE_LIMITED && ColorRange_dest != ColorRange_Compat_e::AVS_COLORRANGE_FULL) {
1335 ColorRange_dest = ColorRange_src;
1336 }
1337 4 bool fulls = ColorRange_src == ColorRange_Compat_e::AVS_COLORRANGE_FULL;
1338 4 bool fulld = ColorRange_dest == ColorRange_Compat_e::AVS_COLORRANGE_FULL;
1339
1340
1341
2/4
✓ Branch 75 → 76 taken 4 times.
✗ Branch 75 → 597 not taken.
✓ Branch 76 → 77 taken 4 times.
✗ Branch 76 → 597 not taken.
4 int dither_type = args[3].AsInt(-1);
1342
2/4
✓ Branch 77 → 78 taken 4 times.
✗ Branch 77 → 597 not taken.
✓ Branch 78 → 79 taken 4 times.
✗ Branch 78 → 597 not taken.
4 bool dither_defined = args[3].Defined();
1343
5/8
✓ Branch 79 → 80 taken 4 times.
✗ Branch 79 → 84 not taken.
✓ Branch 80 → 81 taken 4 times.
✗ Branch 80 → 84 not taken.
✓ Branch 81 → 82 taken 3 times.
✓ Branch 81 → 84 taken 1 time.
✗ Branch 82 → 83 not taken.
✓ Branch 82 → 84 taken 3 times.
4 if(dither_defined && dither_type != 1 && dither_type != 0 && dither_type != -1)
1344 env->ThrowError("ConvertBits: invalid dither type parameter. Only -1 (disabled), 0 (ordered dither) or 1 (Floyd-S) is allowed");
1345
1346
2/2
✓ Branch 84 → 85 taken 1 time.
✓ Branch 84 → 91 taken 3 times.
4 if (dither_type >= 0) {
1347
1/2
✗ Branch 85 → 86 not taken.
✓ Branch 85 → 87 taken 1 time.
1 if (source_bitdepth < target_bitdepth)
1348 env->ThrowError("ConvertBits: dithering is allowed only for scale down");
1349
1/2
✗ Branch 87 → 88 not taken.
✓ Branch 87 → 89 taken 1 time.
1 if (dither_bitdepth > target_bitdepth)
1350 env->ThrowError("ConvertBits: dither_bits must be <= target bitdepth");
1351
1/2
✗ Branch 89 → 90 not taken.
✓ Branch 89 → 91 taken 1 time.
1 if (target_bitdepth == 32)
1352 env->ThrowError("ConvertBits: dithering is not allowed into 32 bit float target");
1353 }
1354
1355 // 3.7.1 t25
1356 // Unfortunately 32 bit float dithering is not implemented, thus we convert to 16 bit
1357 // intermediate clip
1358
1/6
✗ Branch 91 → 92 not taken.
✓ Branch 91 → 126 taken 4 times.
✗ Branch 92 → 93 not taken.
✗ Branch 92 → 94 not taken.
✗ Branch 93 → 94 not taken.
✗ Branch 93 → 126 not taken.
4 if (source_bitdepth == 32 && (dither_type == 0 || dither_type == 1)) {
1359 // c[bits]i[truerange]b[dither]i[dither_bits]i[fulls]b[fulld]b
1360
1361 source_bitdepth = 16;
1362 // solving ordered dither maximum bit depth difference of 8 problem
1363 // by automatic preconversion
1364 if (dither_type == 0 && source_bitdepth - dither_bitdepth > 8) {
1365 source_bitdepth = dither_bitdepth + 8;
1366 if (source_bitdepth % 2)
1367 source_bitdepth--; // must be even
1368 }
1369
1370 AVSValue new_args[7] = { clip, source_bitdepth, true, -1 /* no dither */, AVSValue() /*dither_bits*/, fulls, fulld };
1371 clip = env->Invoke("ConvertBits", AVSValue(new_args, 7)).AsClip();
1372
1373 clip = env->Invoke("Cache", AVSValue(clip)).AsClip();
1374 // and now the source range becomes the previous target
1375 fulls = fulld;
1376 ColorRange_src = ColorRange_dest;
1377 }
1378
1379 // solving ordered dither maximum bit depth difference of 8 problem
1380 // by automatic preconversion
1381
4/6
✓ Branch 126 → 127 taken 4 times.
✗ Branch 126 → 159 not taken.
✓ Branch 127 → 128 taken 1 time.
✓ Branch 127 → 159 taken 3 times.
✓ Branch 128 → 129 taken 1 time.
✗ Branch 128 → 159 not taken.
4 if (source_bitdepth <= 16 && dither_type == 0 && source_bitdepth - dither_bitdepth > 8) {
1382 // c[bits]i[truerange]b[dither]i[dither_bits]i[fulls]b[fulld]b
1383 1 source_bitdepth = dither_bitdepth + 8;
1384
1/2
✓ Branch 129 → 130 taken 1 time.
✗ Branch 129 → 131 not taken.
1 if (source_bitdepth % 2)
1385 1 source_bitdepth--; // must be even
1386
1387
7/18
✓ Branch 131 → 132 taken 1 time.
✗ Branch 131 → 393 not taken.
✓ Branch 132 → 133 taken 1 time.
✗ Branch 132 → 393 not taken.
✓ Branch 133 → 134 taken 1 time.
✗ Branch 133 → 393 not taken.
✓ Branch 134 → 135 taken 1 time.
✗ Branch 134 → 393 not taken.
✓ Branch 135 → 136 taken 1 time.
✗ Branch 135 → 393 not taken.
✓ Branch 136 → 137 taken 1 time.
✗ Branch 136 → 393 not taken.
✓ Branch 137 → 138 taken 1 time.
✗ Branch 137 → 393 not taken.
✗ Branch 393 → 394 not taken.
✗ Branch 393 → 397 not taken.
✗ Branch 395 → 396 not taken.
✗ Branch 395 → 397 not taken.
8 AVSValue new_args[7] = { clip, source_bitdepth, true, -1 /* no dither */, AVSValue() /*dither_bits*/, fulls, fulld };
1388
4/8
✓ Branch 138 → 139 taken 1 time.
✗ Branch 138 → 404 not taken.
✓ Branch 139 → 140 taken 1 time.
✗ Branch 139 → 402 not taken.
✓ Branch 140 → 141 taken 1 time.
✗ Branch 140 → 400 not taken.
✓ Branch 141 → 142 taken 1 time.
✗ Branch 141 → 398 not taken.
1 clip = env->Invoke("ConvertBits", AVSValue(new_args, 7)).AsClip();
1389
1390
4/8
✓ Branch 145 → 146 taken 1 time.
✗ Branch 145 → 413 not taken.
✓ Branch 146 → 147 taken 1 time.
✗ Branch 146 → 411 not taken.
✓ Branch 147 → 148 taken 1 time.
✗ Branch 147 → 409 not taken.
✓ Branch 148 → 149 taken 1 time.
✗ Branch 148 → 407 not taken.
1 clip = env->Invoke("Cache", AVSValue(clip)).AsClip();
1391 // and now the source range becomes the previous target
1392 1 fulls = fulld;
1393 1 ColorRange_src = ColorRange_dest;
1394
2/4
✓ Branch 153 → 154 taken 7 times.
✓ Branch 153 → 157 taken 1 time.
✗ Branch 417 → 418 not taken.
✗ Branch 417 → 421 not taken.
8 }
1395
1396
1/2
✗ Branch 159 → 160 not taken.
✓ Branch 159 → 161 taken 4 times.
4 if (source_bitdepth == dither_bitdepth)
1397 dither_type = -1; // ignore dithering
1398
1399
2/2
✓ Branch 161 → 162 taken 1 time.
✓ Branch 161 → 167 taken 3 times.
4 if(dither_type == 0) {
1400
2/4
✓ Branch 162 → 163 taken 1 time.
✗ Branch 162 → 164 not taken.
✗ Branch 163 → 164 not taken.
✓ Branch 163 → 165 taken 1 time.
1 if (dither_bitdepth < 1 || dither_bitdepth > 16)
1401 env->ThrowError("ConvertBits: ordered dither: invalid dither_bits specified (1-16 allowed)");
1402
1403 // this error message cannot appear if the automatic bit depth reducing conversions above are done
1404
1/2
✗ Branch 165 → 166 not taken.
✓ Branch 165 → 167 taken 1 time.
1 if(source_bitdepth - dither_bitdepth > 8)
1405 env->ThrowError("ConvertBits: dither_bits cannot differ with more than 8 bits from source");
1406 }
1407
1408 // floyd
1409
1/2
✗ Branch 167 → 168 not taken.
✓ Branch 167 → 171 taken 4 times.
4 if (dither_type == 1) {
1410 if (dither_bitdepth < 1 || dither_bitdepth > 16)
1411 env->ThrowError("ConvertBits: Floyd-S: invalid dither_bits specified (1-16 allowed)");
1412 }
1413
1414 // no change -> return unmodified if no transform required
1415
1/2
✗ Branch 171 → 172 not taken.
✓ Branch 171 → 177 taken 4 times.
4 if (source_bitdepth == target_bitdepth) { // 10->10 .. 16->16
1416 if((dither_type < 0 || dither_bitdepth == target_bitdepth) && fulls == fulld)
1417 return clip;
1418 }
1419
1420 // YUY2 conversion is limited
1421
2/4
✓ Branch 177 → 178 taken 4 times.
✗ Branch 177 → 597 not taken.
✗ Branch 178 → 179 not taken.
✓ Branch 178 → 181 taken 4 times.
4 if (vi.IsYUY2()) {
1422 if (target_bitdepth != 8)
1423 env->ThrowError("ConvertBits: YUY2 input must stay in 8 bits");
1424 }
1425
1426
2/4
✓ Branch 181 → 182 taken 4 times.
✗ Branch 181 → 597 not taken.
✗ Branch 182 → 183 not taken.
✓ Branch 182 → 185 taken 4 times.
4 if (vi.IsYV411()) {
1427 if (target_bitdepth != 8)
1428 env->ThrowError("ConvertBits: YV411 input must stay in 8 bits");
1429 }
1430
1431 // packed RGB conversion is limited
1432
3/10
✓ Branch 185 → 186 taken 4 times.
✗ Branch 185 → 597 not taken.
✗ Branch 186 → 187 not taken.
✓ Branch 186 → 190 taken 4 times.
✗ Branch 187 → 188 not taken.
✗ Branch 187 → 597 not taken.
✗ Branch 188 → 189 not taken.
✗ Branch 188 → 190 not taken.
✗ Branch 191 → 192 not taken.
✓ Branch 191 → 195 taken 4 times.
4 if (vi.IsRGB() && !vi.IsPlanar()) {
1433 if (target_bitdepth != 8 && target_bitdepth != 16)
1434 env->ThrowError("ConvertBits: invalid bit-depth for packed RGB formats, only 8 or 16 possible");
1435 }
1436
1437 // remark
1438 // source_10_bit.ConvertTo16bit(truerange=true) : upscale range
1439 // source_10_bit.ConvertTo16bit(truerange=false) : leaves data, only format conversion
1440 // source_10_bit.ConvertTo16bit(bits=12,truerange=true) : upscale range from 10 to 12
1441 // source_10_bit.ConvertTo16bit(bits=12,truerange=false) : leaves data, only format conversion
1442 // source_16_bit.ConvertTo16bit(bits=10, truerange=true) : downscale range
1443 // source_16_bit.ConvertTo16bit(bits=10, truerange=false) : leaves data, only format conversion
1444
1445 // yuy2 is autoconverted to/from YV16. fulls-fulld and dither to lower bit depths are supported
1446
1/2
✓ Branch 195 → 196 taken 4 times.
✗ Branch 195 → 597 not taken.
4 bool need_convert_yuy2 = vi.IsYUY2();
1447 // for dither, planar rgb conversion happens
1448
2/6
✓ Branch 196 → 197 taken 4 times.
✗ Branch 196 → 597 not taken.
✗ Branch 197 → 198 not taken.
✓ Branch 197 → 200 taken 4 times.
✗ Branch 198 → 199 not taken.
✗ Branch 198 → 200 not taken.
4 bool need_convert_24 = vi.IsRGB24() && dither_type >= 0;
1449
2/6
✓ Branch 201 → 202 taken 4 times.
✗ Branch 201 → 597 not taken.
✗ Branch 202 → 203 not taken.
✓ Branch 202 → 205 taken 4 times.
✗ Branch 203 → 204 not taken.
✗ Branch 203 → 205 not taken.
4 bool need_convert_32 = vi.IsRGB32() && dither_type >= 0;
1450
2/6
✓ Branch 206 → 207 taken 4 times.
✗ Branch 206 → 597 not taken.
✗ Branch 207 → 208 not taken.
✓ Branch 207 → 210 taken 4 times.
✗ Branch 208 → 209 not taken.
✗ Branch 208 → 210 not taken.
4 bool need_convert_48 = vi.IsRGB48() && dither_type >= 0;
1451
2/6
✓ Branch 211 → 212 taken 4 times.
✗ Branch 211 → 597 not taken.
✗ Branch 212 → 213 not taken.
✓ Branch 212 → 215 taken 4 times.
✗ Branch 213 → 214 not taken.
✗ Branch 213 → 215 not taken.
4 bool need_convert_64 = vi.IsRGB64() && dither_type >= 0;
1452
1453 // convert to planar on the fly if dither was asked
1454
2/4
✓ Branch 216 → 217 taken 4 times.
✗ Branch 216 → 218 not taken.
✗ Branch 217 → 218 not taken.
✓ Branch 217 → 233 taken 4 times.
4 if (need_convert_24 || need_convert_48) {
1455 AVSValue new_args[1] = { clip };
1456 clip = env->Invoke("ConvertToPlanarRGB", AVSValue(new_args, 1)).AsClip();
1457 }
1458
2/4
✓ Branch 233 → 234 taken 4 times.
✗ Branch 233 → 235 not taken.
✗ Branch 234 → 235 not taken.
✓ Branch 234 → 250 taken 4 times.
4 else if (need_convert_32 || need_convert_64) {
1459 AVSValue new_args[1] = { clip };
1460 clip = env->Invoke("ConvertToPlanarRGBA", AVSValue(new_args, 1)).AsClip();
1461 }
1462
1/2
✗ Branch 250 → 251 not taken.
✓ Branch 250 → 266 taken 4 times.
4 else if (need_convert_yuy2) {
1463 AVSValue new_args[1] = { clip };
1464 clip = env->Invoke("ConvertToYV16", AVSValue(new_args, 1)).AsClip();
1465 }
1466
1467
5/12
✓ Branch 266 → 267 taken 4 times.
✗ Branch 266 → 597 not taken.
✓ Branch 267 → 268 taken 4 times.
✗ Branch 267 → 492 not taken.
✓ Branch 268 → 269 taken 4 times.
✗ Branch 268 → 490 not taken.
✓ Branch 269 → 270 taken 4 times.
✗ Branch 269 → 490 not taken.
✗ Branch 271 → 272 not taken.
✓ Branch 271 → 273 taken 4 times.
✗ Branch 493 → 494 not taken.
✗ Branch 493 → 495 not taken.
4 AVSValue result = new ConvertBits(clip, dither_type, target_bitdepth, assume_truerange, ColorRange_src, ColorRange_dest, dither_bitdepth, env);
1468
1469 // convert back to packed rgb from planar on the fly
1470
2/4
✓ Branch 273 → 274 taken 4 times.
✗ Branch 273 → 275 not taken.
✗ Branch 274 → 275 not taken.
✓ Branch 274 → 304 taken 4 times.
4 if (need_convert_24 || need_convert_48) {
1471 AVSValue new_args[1] = { result };
1472 if(target_bitdepth == 8)
1473 result = env->Invoke("ConvertToRGB24", AVSValue(new_args, 1)).AsClip();
1474 else
1475 result = env->Invoke("ConvertToRGB48", AVSValue(new_args, 1)).AsClip();
1476
2/8
✗ Branch 298 → 299 not taken.
✗ Branch 298 → 302 not taken.
✓ Branch 304 → 305 taken 4 times.
✗ Branch 304 → 306 not taken.
✗ Branch 305 → 306 not taken.
✓ Branch 305 → 335 taken 4 times.
✗ Branch 526 → 527 not taken.
✗ Branch 526 → 530 not taken.
4 } else if (need_convert_32 || need_convert_64) {
1477 AVSValue new_args[1] = { result };
1478 if (target_bitdepth == 8)
1479 result = env->Invoke("ConvertToRGB32", AVSValue(new_args, 1)).AsClip();
1480 else
1481 result = env->Invoke("ConvertToRGB64", AVSValue(new_args, 1)).AsClip();
1482 }
1483
1/2
✗ Branch 335 → 336 not taken.
✓ Branch 335 → 353 taken 4 times.
4 else if (need_convert_yuy2) {
1484 AVSValue new_args[1] = { result };
1485 result = env->Invoke("ConvertToYUY2", AVSValue(new_args, 1)).AsClip();
1486 }
1487
1488
1/2
✓ Branch 353 → 354 taken 4 times.
✗ Branch 353 → 595 not taken.
4 return result;
1489 4 }
1490
1491
1492 4 PVideoFrame __stdcall ConvertBits::GetFrame(int n, IScriptEnvironment* env) {
1493
1/2
✓ Branch 3 → 4 taken 4 times.
✗ Branch 3 → 128 not taken.
4 PVideoFrame src = child->GetFrame(n, env);
1494
1495
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 10 taken 4 times.
4 if (format_change_only)
1496 {
1497 // for 10-16 bit: simple format override in constructor
1498 env->MakeWritable(&src);
1499 src->AmendPixelType(vi.pixel_type);
1500 return src;
1501 }
1502
1503
1/2
✓ Branch 10 → 11 taken 4 times.
✗ Branch 10 → 126 not taken.
4 PVideoFrame dst = env->NewVideoFrameP(vi, &src);
1504
1505
1/2
✓ Branch 11 → 12 taken 4 times.
✗ Branch 11 → 124 not taken.
4 auto props = env->getFramePropsRW(dst);
1506
3/4
✓ Branch 12 → 13 taken 2 times.
✓ Branch 12 → 14 taken 2 times.
✓ Branch 15 → 16 taken 4 times.
✗ Branch 15 → 124 not taken.
4 update_ColorRange(props, fulld ? ColorRange_Compat_e::AVS_COLORRANGE_FULL : ColorRange_Compat_e::AVS_COLORRANGE_LIMITED, env);
1507
1508
2/4
✓ Branch 16 → 17 taken 4 times.
✗ Branch 16 → 124 not taken.
✓ Branch 17 → 18 taken 4 times.
✗ Branch 17 → 104 not taken.
4 if(vi.IsPlanar())
1509 {
1510 4 int planes_y[4] = { PLANAR_Y, PLANAR_U, PLANAR_V, PLANAR_A };
1511 4 int planes_r[4] = { PLANAR_G, PLANAR_B, PLANAR_R, PLANAR_A };
1512
2/8
✓ Branch 18 → 19 taken 4 times.
✗ Branch 18 → 123 not taken.
✗ Branch 19 → 20 not taken.
✓ Branch 19 → 22 taken 4 times.
✗ Branch 20 → 21 not taken.
✗ Branch 20 → 123 not taken.
✗ Branch 21 → 22 not taken.
✗ Branch 21 → 23 not taken.
4 int *planes = (vi.IsYUV() || vi.IsYUVA()) ? planes_y : planes_r;
1513
3/4
✓ Branch 101 → 102 taken 8 times.
✗ Branch 101 → 123 not taken.
✓ Branch 102 → 25 taken 4 times.
✓ Branch 102 → 103 taken 4 times.
8 for (int p = 0; p < vi.NumComponents(); ++p) {
1514 4 const int plane = planes[p];
1515
1/2
✗ Branch 25 → 26 not taken.
✓ Branch 25 → 53 taken 4 times.
4 if (plane == PLANAR_A) {
1516 if (conv_function_a == nullptr)
1517 env->BitBlt(dst->GetWritePtr(plane), dst->GetPitch(plane), src->GetReadPtr(plane), src->GetPitch(plane), src->GetRowSize(plane), src->GetHeight(plane));
1518 else
1519 conv_function_a(src->GetReadPtr(plane), dst->GetWritePtr(plane),
1520 src->GetRowSize(plane), src->GetHeight(plane),
1521 src->GetPitch(plane), dst->GetPitch(plane),
1522 bits_per_pixel, target_bitdepth, dither_bitdepth
1523 );
1524 }
1525
1/2
✗ Branch 53 → 54 not taken.
✓ Branch 53 → 67 taken 4 times.
4 else if (conv_function == nullptr)
1526 env->BitBlt(dst->GetWritePtr(plane), dst->GetPitch(plane), src->GetReadPtr(plane), src->GetPitch(plane), src->GetRowSize(plane), src->GetHeight(plane));
1527 else {
1528
2/4
✓ Branch 67 → 68 taken 4 times.
✗ Branch 67 → 69 not taken.
✗ Branch 68 → 69 not taken.
✓ Branch 68 → 70 taken 4 times.
4 const bool chroma = (plane == PLANAR_U || plane == PLANAR_V);
1529
1/4
✗ Branch 71 → 72 not taken.
✓ Branch 71 → 87 taken 4 times.
✗ Branch 72 → 73 not taken.
✗ Branch 72 → 87 not taken.
4 if (chroma && conv_function_chroma != nullptr)
1530 // 32bit float and 8-16 when full-range involved needs separate signed-aware conversion
1531 conv_function_chroma(src->GetReadPtr(plane), dst->GetWritePtr(plane),
1532 src->GetRowSize(plane), src->GetHeight(plane),
1533 src->GetPitch(plane), dst->GetPitch(plane),
1534 bits_per_pixel, target_bitdepth, dither_bitdepth);
1535 else
1536
7/14
✓ Branch 88 → 89 taken 4 times.
✗ Branch 88 → 123 not taken.
✓ Branch 90 → 91 taken 4 times.
✗ Branch 90 → 123 not taken.
✓ Branch 92 → 93 taken 4 times.
✗ Branch 92 → 123 not taken.
✓ Branch 94 → 95 taken 4 times.
✗ Branch 94 → 123 not taken.
✓ Branch 96 → 97 taken 4 times.
✗ Branch 96 → 123 not taken.
✓ Branch 98 → 99 taken 4 times.
✗ Branch 98 → 123 not taken.
✓ Branch 99 → 100 taken 4 times.
✗ Branch 99 → 123 not taken.
4 conv_function(src->GetReadPtr(plane), dst->GetWritePtr(plane),
1537 src->GetRowSize(plane), src->GetHeight(plane),
1538 src->GetPitch(plane), dst->GetPitch(plane),
1539 bits_per_pixel, target_bitdepth, dither_bitdepth);
1540 }
1541 }
1542 }
1543 else {
1544 // packed RGBs
1545 conv_function(src->GetReadPtr(), dst->GetWritePtr(),
1546 src->GetRowSize(), src->GetHeight(),
1547 src->GetPitch(), dst->GetPitch(),
1548 bits_per_pixel, target_bitdepth, dither_bitdepth);
1549 }
1550
1/2
✓ Branch 117 → 118 taken 4 times.
✗ Branch 117 → 124 not taken.
4 return dst;
1551 4 }
1552