Line data Source code
1 : /******************************************************************************
2 : * $Id$
3 : *
4 : * Project: GDAL Core
5 : * Purpose: Inline C++ templates
6 : * Author: Phil Vachon, <philippe at cowpig.ca>
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2009, Phil Vachon, <philippe at cowpig.ca>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #ifndef GDAL_PRIV_TEMPLATES_HPP_INCLUDED
31 : #define GDAL_PRIV_TEMPLATES_HPP_INCLUDED
32 :
33 : #include "cpl_port.h"
34 :
35 : #include <cstdint>
36 : #include <limits>
37 :
38 : /************************************************************************/
39 : /* GDALGetDataLimits() */
40 : /************************************************************************/
41 : /**
42 : * Compute the limits of values that can be placed in Tout in terms of
43 : * Tin. Usually used for output clamping, when the output data type's
44 : * limits are stable relative to the input type (i.e. no roundoff error).
45 : *
46 : * @param tMaxValue the returned maximum value
47 : * @param tMinValue the returned minimum value
48 : */
49 :
50 : template <class Tin, class Tout>
51 270247668 : inline void GDALGetDataLimits(Tin &tMaxValue, Tin &tMinValue)
52 : {
53 270247668 : tMaxValue = std::numeric_limits<Tin>::max();
54 269676138 : tMinValue = std::numeric_limits<Tin>::min();
55 :
56 : // Compute the actual minimum value of Tout in terms of Tin.
57 : if constexpr (std::numeric_limits<Tout>::is_signed &&
58 : std::numeric_limits<Tout>::is_integer)
59 : {
60 : // the minimum value is less than zero
61 : if constexpr (std::numeric_limits<Tout>::digits <
62 : std::numeric_limits<Tin>::digits ||
63 : !std::numeric_limits<Tin>::is_integer)
64 : {
65 : // Tout is smaller than Tin, so we need to clamp values in input
66 : // to the range of Tout's min/max values
67 : if (std::numeric_limits<Tin>::is_signed)
68 : {
69 78394145 : tMinValue = static_cast<Tin>(std::numeric_limits<Tout>::min());
70 : }
71 78750534 : tMaxValue = static_cast<Tin>(std::numeric_limits<Tout>::max());
72 : }
73 : }
74 : else if constexpr (std::numeric_limits<Tout>::is_integer)
75 : {
76 : // the output is unsigned, so we just need to determine the max
77 : /* coverity[same_on_both_sides] */
78 : if constexpr (std::numeric_limits<Tout>::digits <=
79 : std::numeric_limits<Tin>::digits)
80 : {
81 : // Tout is smaller than Tin, so we need to clamp the input values
82 : // to the range of Tout's max
83 129332308 : tMaxValue = static_cast<Tin>(std::numeric_limits<Tout>::max());
84 : }
85 130854203 : tMinValue = 0;
86 : }
87 268649068 : }
88 :
89 : /************************************************************************/
90 : /* GDALClampValue() */
91 : /************************************************************************/
92 : /**
93 : * Clamp values of type T to a specified range
94 : *
95 : * @param tValue the value
96 : * @param tMax the max value
97 : * @param tMin the min value
98 : */
99 : template <class T>
100 268743921 : inline T GDALClampValue(const T tValue, const T tMax, const T tMin)
101 : {
102 268743921 : return tValue > tMax ? tMax : tValue < tMin ? tMin : tValue;
103 : }
104 :
105 : /************************************************************************/
106 : /* GDALClampDoubleValue() */
107 : /************************************************************************/
108 : /**
109 : * Clamp double values to a specified range, this uses the same
110 : * argument ordering as std::clamp, returns TRUE if the value was clamped.
111 : *
112 : * @param tValue the value
113 : * @param tMin the min value
114 : * @param tMax the max value
115 : *
116 : */
117 : template <class T2, class T3>
118 155 : inline bool GDALClampDoubleValue(double &tValue, const T2 tMin, const T3 tMax)
119 : {
120 155 : const double tMin2{static_cast<double>(tMin)};
121 155 : const double tMax2{static_cast<double>(tMax)};
122 155 : if (tValue > tMax2 || tValue < tMin2)
123 : {
124 22 : tValue = tValue > tMax2 ? tMax2 : tValue < tMin2 ? tMin2 : tValue;
125 22 : return true;
126 : }
127 : else
128 : {
129 133 : return false;
130 : }
131 : }
132 :
133 : /************************************************************************/
134 : /* GDALIsValueInRange() */
135 : /************************************************************************/
136 : /**
137 : * Returns whether a value is in the type range.
138 : * NaN is considered not to be in type range.
139 : *
140 : * @param dfValue the value
141 : * @return whether the value is in the type range.
142 : */
143 105225 : template <class T> inline bool GDALIsValueInRange(double dfValue)
144 : {
145 210426 : return dfValue >= static_cast<double>(std::numeric_limits<T>::lowest()) &&
146 210426 : dfValue <= static_cast<double>(std::numeric_limits<T>::max());
147 : }
148 :
149 3 : template <> inline bool GDALIsValueInRange<double>(double dfValue)
150 : {
151 3 : return !CPLIsNan(dfValue);
152 : }
153 :
154 41595 : template <> inline bool GDALIsValueInRange<float>(double dfValue)
155 : {
156 41185 : return CPLIsInf(dfValue) ||
157 41266 : (dfValue >= -std::numeric_limits<float>::max() &&
158 124522 : dfValue <= std::numeric_limits<float>::max());
159 : }
160 :
161 : /************************************************************************/
162 : /* GDALCopyWord() */
163 : /************************************************************************/
164 :
165 : template <class Tin, class Tout> struct sGDALCopyWord
166 : {
167 117440814 : static inline void f(const Tin tValueIn, Tout &tValueOut)
168 : {
169 : Tin tMaxVal, tMinVal;
170 117440814 : GDALGetDataLimits<Tin, Tout>(tMaxVal, tMinVal);
171 117440714 : tValueOut =
172 117423914 : static_cast<Tout>(GDALClampValue(tValueIn, tMaxVal, tMinVal));
173 117440714 : }
174 : };
175 :
176 : template <class Tin> struct sGDALCopyWord<Tin, float>
177 : {
178 12302717 : static inline void f(const Tin tValueIn, float &fValueOut)
179 : {
180 12302717 : fValueOut = static_cast<float>(tValueIn);
181 12302717 : }
182 : };
183 :
184 : template <class Tin> struct sGDALCopyWord<Tin, double>
185 : {
186 62778742 : static inline void f(const Tin tValueIn, double &dfValueOut)
187 : {
188 62778742 : dfValueOut = static_cast<double>(tValueIn);
189 62778742 : }
190 : };
191 :
192 : template <> struct sGDALCopyWord<double, double>
193 : {
194 6753460 : static inline void f(const double dfValueIn, double &dfValueOut)
195 : {
196 6753460 : dfValueOut = dfValueIn;
197 6753460 : }
198 : };
199 :
200 : template <> struct sGDALCopyWord<float, float>
201 : {
202 7838140 : static inline void f(const float fValueIn, float &fValueOut)
203 : {
204 7838140 : fValueOut = fValueIn;
205 7838140 : }
206 : };
207 :
208 : template <> struct sGDALCopyWord<float, double>
209 : {
210 46436300 : static inline void f(const float fValueIn, double &dfValueOut)
211 : {
212 46436300 : dfValueOut = fValueIn;
213 46436300 : }
214 : };
215 :
216 : template <> struct sGDALCopyWord<double, float>
217 : {
218 2305620 : static inline void f(const double dfValueIn, float &fValueOut)
219 : {
220 2305620 : if (dfValueIn > std::numeric_limits<float>::max())
221 : {
222 44 : fValueOut = std::numeric_limits<float>::infinity();
223 44 : return;
224 : }
225 2305580 : if (dfValueIn < -std::numeric_limits<float>::max())
226 : {
227 46 : fValueOut = -std::numeric_limits<float>::infinity();
228 46 : return;
229 : }
230 :
231 2305530 : fValueOut = static_cast<float>(dfValueIn);
232 : }
233 : };
234 :
235 : template <class Tout> struct sGDALCopyWord<float, Tout>
236 : {
237 3745760 : static inline void f(const float fValueIn, Tout &tValueOut)
238 : {
239 3745760 : if (CPLIsNan(fValueIn))
240 : {
241 0 : tValueOut = 0;
242 0 : return;
243 : }
244 : float fMaxVal, fMinVal;
245 3745760 : GDALGetDataLimits<float, Tout>(fMaxVal, fMinVal);
246 3745690 : tValueOut = static_cast<Tout>(
247 3745670 : GDALClampValue(fValueIn + 0.5f, fMaxVal, fMinVal));
248 : }
249 : };
250 :
251 : template <> struct sGDALCopyWord<float, short>
252 : {
253 2928220 : static inline void f(const float fValueIn, short &nValueOut)
254 : {
255 2928220 : if (CPLIsNan(fValueIn))
256 : {
257 0 : nValueOut = 0;
258 0 : return;
259 : }
260 : float fMaxVal, fMinVal;
261 2928220 : GDALGetDataLimits<float, short>(fMaxVal, fMinVal);
262 2928220 : float fValue = fValueIn >= 0.0f ? fValueIn + 0.5f : fValueIn - 0.5f;
263 2928220 : nValueOut =
264 2928220 : static_cast<short>(GDALClampValue(fValue, fMaxVal, fMinVal));
265 : }
266 : };
267 :
268 : template <> struct sGDALCopyWord<float, signed char>
269 : {
270 221 : static inline void f(const float fValueIn, signed char &nValueOut)
271 : {
272 221 : if (CPLIsNan(fValueIn))
273 : {
274 0 : nValueOut = 0;
275 0 : return;
276 : }
277 : float fMaxVal, fMinVal;
278 221 : GDALGetDataLimits<float, signed char>(fMaxVal, fMinVal);
279 221 : float fValue = fValueIn >= 0.0f ? fValueIn + 0.5f : fValueIn - 0.5f;
280 221 : nValueOut =
281 221 : static_cast<signed char>(GDALClampValue(fValue, fMaxVal, fMinVal));
282 : }
283 : };
284 :
285 : template <class Tout> struct sGDALCopyWord<double, Tout>
286 : {
287 70332083 : static inline void f(const double dfValueIn, Tout &tValueOut)
288 : {
289 70332083 : if (CPLIsNan(dfValueIn))
290 : {
291 0 : tValueOut = 0;
292 0 : return;
293 : }
294 : double dfMaxVal, dfMinVal;
295 70332083 : GDALGetDataLimits<double, Tout>(dfMaxVal, dfMinVal);
296 69492983 : tValueOut = static_cast<Tout>(
297 68809783 : GDALClampValue(dfValueIn + 0.5, dfMaxVal, dfMinVal));
298 : }
299 : };
300 :
301 : template <> struct sGDALCopyWord<double, int>
302 : {
303 70358200 : static inline void f(const double dfValueIn, int &nValueOut)
304 : {
305 70358200 : if (CPLIsNan(dfValueIn))
306 : {
307 0 : nValueOut = 0;
308 0 : return;
309 : }
310 : double dfMaxVal, dfMinVal;
311 70358200 : GDALGetDataLimits<double, int>(dfMaxVal, dfMinVal);
312 70358200 : double dfValue = dfValueIn >= 0.0 ? dfValueIn + 0.5 : dfValueIn - 0.5;
313 70358200 : nValueOut =
314 70358200 : static_cast<int>(GDALClampValue(dfValue, dfMaxVal, dfMinVal));
315 : }
316 : };
317 :
318 : template <> struct sGDALCopyWord<double, std::int64_t>
319 : {
320 589 : static inline void f(const double dfValueIn, std::int64_t &nValueOut)
321 : {
322 589 : if (CPLIsNan(dfValueIn))
323 : {
324 0 : nValueOut = 0;
325 0 : return;
326 : }
327 : double dfMaxVal, dfMinVal;
328 589 : GDALGetDataLimits<double, std::int64_t>(dfMaxVal, dfMinVal);
329 589 : double dfValue = dfValueIn >= 0.0 ? dfValueIn + 0.5 : dfValueIn - 0.5;
330 589 : nValueOut = static_cast<std::int64_t>(
331 589 : GDALClampValue(dfValue, dfMaxVal, dfMinVal));
332 : }
333 : };
334 :
335 : template <> struct sGDALCopyWord<double, short>
336 : {
337 5102140 : static inline void f(const double dfValueIn, short &nValueOut)
338 : {
339 5102140 : if (CPLIsNan(dfValueIn))
340 : {
341 0 : nValueOut = 0;
342 0 : return;
343 : }
344 : double dfMaxVal, dfMinVal;
345 5102140 : GDALGetDataLimits<double, short>(dfMaxVal, dfMinVal);
346 5102140 : double dfValue = dfValueIn > 0.0 ? dfValueIn + 0.5 : dfValueIn - 0.5;
347 5102140 : nValueOut =
348 5102140 : static_cast<short>(GDALClampValue(dfValue, dfMaxVal, dfMinVal));
349 : }
350 : };
351 :
352 : template <> struct sGDALCopyWord<double, signed char>
353 : {
354 441 : static inline void f(const double dfValueIn, signed char &nValueOut)
355 : {
356 441 : if (CPLIsNan(dfValueIn))
357 : {
358 0 : nValueOut = 0;
359 0 : return;
360 : }
361 : double dfMaxVal, dfMinVal;
362 441 : GDALGetDataLimits<double, signed char>(dfMaxVal, dfMinVal);
363 441 : double dfValue = dfValueIn > 0.0 ? dfValueIn + 0.5 : dfValueIn - 0.5;
364 441 : nValueOut = static_cast<signed char>(
365 441 : GDALClampValue(dfValue, dfMaxVal, dfMinVal));
366 : }
367 : };
368 :
369 : // Roundoff occurs for Float32 -> int32 for max/min. Overload GDALCopyWord
370 : // specifically for this case.
371 : template <> struct sGDALCopyWord<float, int>
372 : {
373 134016000 : static inline void f(const float fValueIn, int &nValueOut)
374 : {
375 134016000 : if (fValueIn >= static_cast<float>(std::numeric_limits<int>::max()))
376 : {
377 32 : nValueOut = std::numeric_limits<int>::max();
378 : }
379 132209000 : else if (fValueIn <=
380 135685000 : static_cast<float>(std::numeric_limits<int>::min()))
381 : {
382 0 : nValueOut = std::numeric_limits<int>::min();
383 : }
384 : else
385 : {
386 134993000 : nValueOut = static_cast<int>(fValueIn > 0.0f ? fValueIn + 0.5f
387 121179 : : fValueIn - 0.5f);
388 : }
389 134872000 : }
390 : };
391 :
392 : // Roundoff occurs for Float32 -> uint32 for max. Overload GDALCopyWord
393 : // specifically for this case.
394 : template <> struct sGDALCopyWord<float, unsigned int>
395 : {
396 540 : static inline void f(const float fValueIn, unsigned int &nValueOut)
397 : {
398 540 : if (fValueIn >=
399 540 : static_cast<float>(std::numeric_limits<unsigned int>::max()))
400 : {
401 20 : nValueOut = std::numeric_limits<unsigned int>::max();
402 : }
403 520 : else if (fValueIn <=
404 520 : static_cast<float>(std::numeric_limits<unsigned int>::min()))
405 : {
406 42 : nValueOut = std::numeric_limits<unsigned int>::min();
407 : }
408 : else
409 : {
410 478 : nValueOut = static_cast<unsigned int>(fValueIn + 0.5f);
411 : }
412 540 : }
413 : };
414 :
415 : // Roundoff occurs for Float32 -> std::int64_t for max/min. Overload
416 : // GDALCopyWord specifically for this case.
417 : template <> struct sGDALCopyWord<float, std::int64_t>
418 : {
419 222 : static inline void f(const float fValueIn, std::int64_t &nValueOut)
420 : {
421 222 : if (fValueIn >=
422 222 : static_cast<float>(std::numeric_limits<std::int64_t>::max()))
423 : {
424 0 : nValueOut = std::numeric_limits<std::int64_t>::max();
425 : }
426 222 : else if (fValueIn <=
427 222 : static_cast<float>(std::numeric_limits<std::int64_t>::min()))
428 : {
429 0 : nValueOut = std::numeric_limits<std::int64_t>::min();
430 : }
431 : else
432 : {
433 444 : nValueOut = static_cast<std::int64_t>(
434 222 : fValueIn > 0.0f ? fValueIn + 0.5f : fValueIn - 0.5f);
435 : }
436 222 : }
437 : };
438 :
439 : // Roundoff occurs for Float32 -> std::uint64_t for max. Overload GDALCopyWord
440 : // specifically for this case.
441 : template <> struct sGDALCopyWord<float, std::uint64_t>
442 : {
443 152 : static inline void f(const float fValueIn, std::uint64_t &nValueOut)
444 : {
445 152 : if (fValueIn >=
446 152 : static_cast<float>(std::numeric_limits<std::uint64_t>::max()))
447 : {
448 0 : nValueOut = std::numeric_limits<std::uint64_t>::max();
449 : }
450 152 : else if (fValueIn <=
451 152 : static_cast<float>(std::numeric_limits<std::uint64_t>::min()))
452 : {
453 0 : nValueOut = std::numeric_limits<std::uint64_t>::min();
454 : }
455 : else
456 : {
457 152 : nValueOut = static_cast<std::uint64_t>(fValueIn + 0.5f);
458 : }
459 152 : }
460 : };
461 :
462 : /**
463 : * Copy a single word, optionally rounding if appropriate (i.e. going
464 : * from the float to the integer case). Note that this is the function
465 : * you should specialize if you're adding a new data type.
466 : *
467 : * @param tValueIn value of type Tin; the input value to be converted
468 : * @param tValueOut value of type Tout; the output value
469 : */
470 :
471 : template <class Tin, class Tout>
472 541449181 : inline void GDALCopyWord(const Tin tValueIn, Tout &tValueOut)
473 : {
474 541449181 : sGDALCopyWord<Tin, Tout>::f(tValueIn, tValueOut);
475 541186701 : }
476 :
477 : /************************************************************************/
478 : /* GDALCopy4Words() */
479 : /************************************************************************/
480 : /**
481 : * Copy 4 packed words to 4 packed words, optionally rounding if appropriate
482 : * (i.e. going from the float to the integer case).
483 : *
484 : * @param pValueIn pointer to 4 input values of type Tin.
485 : * @param pValueOut pointer to 4 output values of type Tout.
486 : */
487 :
488 : template <class Tin, class Tout>
489 16 : inline void GDALCopy4Words(const Tin *pValueIn, Tout *const pValueOut)
490 : {
491 16 : GDALCopyWord(pValueIn[0], pValueOut[0]);
492 16 : GDALCopyWord(pValueIn[1], pValueOut[1]);
493 16 : GDALCopyWord(pValueIn[2], pValueOut[2]);
494 16 : GDALCopyWord(pValueIn[3], pValueOut[3]);
495 16 : }
496 :
497 : /************************************************************************/
498 : /* GDALCopy8Words() */
499 : /************************************************************************/
500 : /**
501 : * Copy 8 packed words to 8 packed words, optionally rounding if appropriate
502 : * (i.e. going from the float to the integer case).
503 : *
504 : * @param pValueIn pointer to 8 input values of type Tin.
505 : * @param pValueOut pointer to 8 output values of type Tout.
506 : */
507 :
508 : template <class Tin, class Tout>
509 13031190 : inline void GDALCopy8Words(const Tin *pValueIn, Tout *const pValueOut)
510 : {
511 13031190 : GDALCopy4Words(pValueIn, pValueOut);
512 13031690 : GDALCopy4Words(pValueIn + 4, pValueOut + 4);
513 13031390 : }
514 :
515 : // Needs SSE2
516 : #if defined(__x86_64) || defined(_M_X64) || defined(USE_SSE2)
517 :
518 : #include <emmintrin.h>
519 :
520 31996105 : static inline void GDALCopyXMMToInt32(const __m128i xmm, void *pDest)
521 : {
522 31996105 : int n32 = _mm_cvtsi128_si32(xmm); // Extract lower 32 bit word
523 31996105 : memcpy(pDest, &n32, sizeof(n32));
524 31996105 : }
525 :
526 73833095 : static inline void GDALCopyXMMToInt64(const __m128i xmm, void *pDest)
527 : {
528 : _mm_storel_epi64(reinterpret_cast<__m128i *>(pDest), xmm);
529 73833095 : }
530 :
531 : #if __SSSE3__
532 : #include <tmmintrin.h>
533 : #endif
534 :
535 : #if __SSE4_1__
536 : #include <smmintrin.h>
537 : #endif
538 :
539 : template <>
540 25851302 : inline void GDALCopy4Words(const float *pValueIn, GByte *const pValueOut)
541 : {
542 25851302 : __m128 xmm = _mm_loadu_ps(pValueIn);
543 :
544 : // The following clamping would be useless due to the final saturating
545 : // packing if we could guarantee the input range in [INT_MIN,INT_MAX]
546 25851302 : const __m128 p0d5 = _mm_set1_ps(0.5f);
547 25851302 : const __m128 xmm_max = _mm_set1_ps(255);
548 25851302 : xmm = _mm_add_ps(xmm, p0d5);
549 51703404 : xmm = _mm_min_ps(_mm_max_ps(xmm, p0d5), xmm_max);
550 :
551 25854002 : __m128i xmm_i = _mm_cvttps_epi32(xmm);
552 :
553 : #if __SSSE3__
554 : xmm_i = _mm_shuffle_epi8(
555 : xmm_i, _mm_cvtsi32_si128(0 | (4 << 8) | (8 << 16) | (12 << 24)));
556 : #else
557 25849902 : xmm_i = _mm_packs_epi32(xmm_i, xmm_i); // Pack int32 to int16
558 25853102 : xmm_i = _mm_packus_epi16(xmm_i, xmm_i); // Pack int16 to uint8
559 : #endif
560 25853102 : GDALCopyXMMToInt32(xmm_i, pValueOut);
561 25854302 : }
562 :
563 : template <>
564 202562 : inline void GDALCopy4Words(const float *pValueIn, GInt16 *const pValueOut)
565 : {
566 202562 : __m128 xmm = _mm_loadu_ps(pValueIn);
567 :
568 202562 : const __m128 xmm_min = _mm_set1_ps(-32768);
569 202562 : const __m128 xmm_max = _mm_set1_ps(32767);
570 405124 : xmm = _mm_min_ps(_mm_max_ps(xmm, xmm_min), xmm_max);
571 :
572 202562 : const __m128 p0d5 = _mm_set1_ps(0.5f);
573 202562 : const __m128 m0d5 = _mm_set1_ps(-0.5f);
574 202562 : const __m128 mask = _mm_cmpge_ps(xmm, p0d5);
575 : // f >= 0.5f ? f + 0.5f : f - 0.5f
576 810248 : xmm = _mm_add_ps(
577 : xmm, _mm_or_ps(_mm_and_ps(mask, p0d5), _mm_andnot_ps(mask, m0d5)));
578 :
579 202562 : __m128i xmm_i = _mm_cvttps_epi32(xmm);
580 :
581 202562 : xmm_i = _mm_packs_epi32(xmm_i, xmm_i); // Pack int32 to int16
582 202562 : GDALCopyXMMToInt64(xmm_i, pValueOut);
583 202562 : }
584 :
585 : template <>
586 1 : inline void GDALCopy4Words(const float *pValueIn, GUInt16 *const pValueOut)
587 : {
588 1 : __m128 xmm = _mm_loadu_ps(pValueIn);
589 :
590 1 : const __m128 p0d5 = _mm_set1_ps(0.5f);
591 1 : const __m128 xmm_max = _mm_set1_ps(65535);
592 1 : xmm = _mm_add_ps(xmm, p0d5);
593 2 : xmm = _mm_min_ps(_mm_max_ps(xmm, p0d5), xmm_max);
594 :
595 1 : __m128i xmm_i = _mm_cvttps_epi32(xmm);
596 :
597 : #if __SSE4_1__
598 : xmm_i = _mm_packus_epi32(xmm_i, xmm_i); // Pack int32 to uint16
599 : #else
600 : // Translate to int16 range because _mm_packus_epi32 is SSE4.1 only
601 2 : xmm_i = _mm_add_epi32(xmm_i, _mm_set1_epi32(-32768));
602 1 : xmm_i = _mm_packs_epi32(xmm_i, xmm_i); // Pack int32 to int16
603 : // Translate back to uint16 range (actually -32768==32768 in int16)
604 1 : xmm_i = _mm_add_epi16(xmm_i, _mm_set1_epi16(-32768));
605 : #endif
606 1 : GDALCopyXMMToInt64(xmm_i, pValueOut);
607 1 : }
608 :
609 : #ifdef __AVX2__
610 :
611 : #include <immintrin.h>
612 :
613 : template <>
614 : inline void GDALCopy8Words(const float *pValueIn, GByte *const pValueOut)
615 : {
616 : __m256 ymm = _mm256_loadu_ps(pValueIn);
617 :
618 : const __m256 p0d5 = _mm256_set1_ps(0.5f);
619 : const __m256 ymm_max = _mm256_set1_ps(255);
620 : ymm = _mm256_add_ps(ymm, p0d5);
621 : ymm = _mm256_min_ps(_mm256_max_ps(ymm, p0d5), ymm_max);
622 :
623 : __m256i ymm_i = _mm256_cvttps_epi32(ymm);
624 :
625 : ymm_i = _mm256_packus_epi32(ymm_i, ymm_i); // Pack int32 to uint16
626 : ymm_i = _mm256_permute4x64_epi64(ymm_i, 0 | (2 << 2)); // AVX2
627 :
628 : __m128i xmm_i = _mm256_castsi256_si128(ymm_i);
629 : xmm_i = _mm_packus_epi16(xmm_i, xmm_i);
630 : GDALCopyXMMToInt64(xmm_i, pValueOut);
631 : }
632 :
633 : template <>
634 : inline void GDALCopy8Words(const float *pValueIn, GUInt16 *const pValueOut)
635 : {
636 : __m256 ymm = _mm256_loadu_ps(pValueIn);
637 :
638 : const __m256 p0d5 = _mm256_set1_ps(0.5f);
639 : const __m256 ymm_max = _mm256_set1_ps(65535);
640 : ymm = _mm256_add_ps(ymm, p0d5);
641 : ymm = _mm256_min_ps(_mm256_max_ps(ymm, p0d5), ymm_max);
642 :
643 : __m256i ymm_i = _mm256_cvttps_epi32(ymm);
644 :
645 : ymm_i = _mm256_packus_epi32(ymm_i, ymm_i); // Pack int32 to uint16
646 : ymm_i = _mm256_permute4x64_epi64(ymm_i, 0 | (2 << 2)); // AVX2
647 :
648 : _mm_storeu_si128(reinterpret_cast<__m128i *>(pValueOut),
649 : _mm256_castsi256_si128(ymm_i));
650 : }
651 : #else
652 : template <>
653 7711511 : inline void GDALCopy8Words(const float *pValueIn, GUInt16 *const pValueOut)
654 : {
655 7711511 : __m128 xmm = _mm_loadu_ps(pValueIn);
656 15423002 : __m128 xmm1 = _mm_loadu_ps(pValueIn + 4);
657 :
658 7711511 : const __m128 p0d5 = _mm_set1_ps(0.5f);
659 7711511 : const __m128 xmm_max = _mm_set1_ps(65535);
660 7711511 : xmm = _mm_add_ps(xmm, p0d5);
661 7711511 : xmm1 = _mm_add_ps(xmm1, p0d5);
662 15453202 : xmm = _mm_min_ps(_mm_max_ps(xmm, p0d5), xmm_max);
663 15469502 : xmm1 = _mm_min_ps(_mm_max_ps(xmm1, p0d5), xmm_max);
664 :
665 7722511 : __m128i xmm_i = _mm_cvttps_epi32(xmm);
666 7744661 : __m128i xmm1_i = _mm_cvttps_epi32(xmm1);
667 :
668 : #if __SSE4_1__
669 : xmm_i = _mm_packus_epi32(xmm_i, xmm1_i); // Pack int32 to uint16
670 : #else
671 : // Translate to int16 range because _mm_packus_epi32 is SSE4.1 only
672 15489302 : xmm_i = _mm_add_epi32(xmm_i, _mm_set1_epi32(-32768));
673 15489302 : xmm1_i = _mm_add_epi32(xmm1_i, _mm_set1_epi32(-32768));
674 7756691 : xmm_i = _mm_packs_epi32(xmm_i, xmm1_i); // Pack int32 to int16
675 : // Translate back to uint16 range (actually -32768==32768 in int16)
676 15513402 : xmm_i = _mm_add_epi16(xmm_i, _mm_set1_epi16(-32768));
677 : #endif
678 : _mm_storeu_si128(reinterpret_cast<__m128i *>(pValueOut), xmm_i);
679 7756691 : }
680 : #endif
681 :
682 : #ifdef notdef_because_slightly_slower_than_default_implementation
683 : template <>
684 : inline void GDALCopy4Words(const double *pValueIn, float *const pValueOut)
685 : {
686 : __m128d float_posmax = _mm_set1_pd(std::numeric_limits<float>::max());
687 : __m128d float_negmax = _mm_set1_pd(-std::numeric_limits<float>::max());
688 : __m128d float_posinf = _mm_set1_pd(std::numeric_limits<float>::infinity());
689 : __m128d float_neginf = _mm_set1_pd(-std::numeric_limits<float>::infinity());
690 : __m128d val01 = _mm_loadu_pd(pValueIn);
691 : __m128d val23 = _mm_loadu_pd(pValueIn + 2);
692 : __m128d mask_max = _mm_cmpge_pd(val01, float_posmax);
693 : __m128d mask_max23 = _mm_cmpge_pd(val23, float_posmax);
694 : val01 = _mm_or_pd(_mm_and_pd(mask_max, float_posinf),
695 : _mm_andnot_pd(mask_max, val01));
696 : val23 = _mm_or_pd(_mm_and_pd(mask_max23, float_posinf),
697 : _mm_andnot_pd(mask_max23, val23));
698 : __m128d mask_min = _mm_cmple_pd(val01, float_negmax);
699 : __m128d mask_min23 = _mm_cmple_pd(val23, float_negmax);
700 : val01 = _mm_or_pd(_mm_and_pd(mask_min, float_neginf),
701 : _mm_andnot_pd(mask_min, val01));
702 : val23 = _mm_or_pd(_mm_and_pd(mask_min23, float_neginf),
703 : _mm_andnot_pd(mask_min23, val23));
704 : __m128 val01_s = _mm_cvtpd_ps(val01);
705 : __m128 val23_s = _mm_cvtpd_ps(val23);
706 : __m128i val01_i = _mm_castps_si128(val01_s);
707 : __m128i val23_i = _mm_castps_si128(val23_s);
708 : GDALCopyXMMToInt64(val01_i, pValueOut);
709 : GDALCopyXMMToInt64(val23_i, pValueOut + 2);
710 : }
711 : #endif
712 :
713 : #endif // defined(__x86_64) || defined(_M_X64)
714 :
715 : #endif // GDAL_PRIV_TEMPLATES_HPP_INCLUDED
|