Coverage Report

Created: 2025-07-23 09:13

/src/gdal/frmts/vrt/pixelfunctions.cpp
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 *
3
 * Project:  GDAL
4
 * Purpose:  Implementation of a set of GDALDerivedPixelFunc(s) to be used
5
 *           with source raster band of virtual GDAL datasets.
6
 * Author:   Antonio Valentino <antonio.valentino@tiscali.it>
7
 *
8
 ******************************************************************************
9
 * Copyright (c) 2008-2014,2022 Antonio Valentino <antonio.valentino@tiscali.it>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 *****************************************************************************/
13
14
#include <array>
15
#include <cmath>
16
#include "gdal.h"
17
#include "vrtdataset.h"
18
#include "vrtexpression.h"
19
#include "vrtreclassifier.h"
20
#include "cpl_float.h"
21
22
#if defined(__x86_64) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
23
#define USE_SSE2
24
#include "gdalsse_priv.h"
25
26
#if !defined(USE_NEON_OPTIMIZATIONS)
27
#define LIBDIVIDE_SSE2
28
#ifdef __GNUC__
29
#pragma GCC diagnostic push
30
#pragma GCC diagnostic ignored "-Wold-style-cast"
31
#pragma GCC diagnostic ignored "-Weffc++"
32
#endif
33
#include "../../third_party/libdivide/libdivide.h"
34
#ifdef __GNUC__
35
#pragma GCC diagnostic pop
36
#endif
37
#endif
38
39
#endif
40
41
#include "gdal_priv_templates.hpp"
42
43
#include <algorithm>
44
#include <cassert>
45
#include <limits>
46
47
namespace gdal
48
{
49
0
MathExpression::~MathExpression() = default;
50
}
51
52
template <typename T>
53
inline double GetSrcVal(const void *pSource, GDALDataType eSrcType, T ii)
54
0
{
55
0
    switch (eSrcType)
56
0
    {
57
0
        case GDT_Unknown:
58
0
            return 0;
59
0
        case GDT_Byte:
60
0
            return static_cast<const GByte *>(pSource)[ii];
61
0
        case GDT_Int8:
62
0
            return static_cast<const GInt8 *>(pSource)[ii];
63
0
        case GDT_UInt16:
64
0
            return static_cast<const GUInt16 *>(pSource)[ii];
65
0
        case GDT_Int16:
66
0
            return static_cast<const GInt16 *>(pSource)[ii];
67
0
        case GDT_UInt32:
68
0
            return static_cast<const GUInt32 *>(pSource)[ii];
69
0
        case GDT_Int32:
70
0
            return static_cast<const GInt32 *>(pSource)[ii];
71
        // Precision loss currently for int64/uint64
72
0
        case GDT_UInt64:
73
0
            return static_cast<double>(
74
0
                static_cast<const uint64_t *>(pSource)[ii]);
75
0
        case GDT_Int64:
76
0
            return static_cast<double>(
77
0
                static_cast<const int64_t *>(pSource)[ii]);
78
0
        case GDT_Float16:
79
0
            return static_cast<const GFloat16 *>(pSource)[ii];
80
0
        case GDT_Float32:
81
0
            return static_cast<const float *>(pSource)[ii];
82
0
        case GDT_Float64:
83
0
            return static_cast<const double *>(pSource)[ii];
84
0
        case GDT_CInt16:
85
0
            return static_cast<const GInt16 *>(pSource)[2 * ii];
86
0
        case GDT_CInt32:
87
0
            return static_cast<const GInt32 *>(pSource)[2 * ii];
88
0
        case GDT_CFloat16:
89
0
            return static_cast<const GFloat16 *>(pSource)[2 * ii];
90
0
        case GDT_CFloat32:
91
0
            return static_cast<const float *>(pSource)[2 * ii];
92
0
        case GDT_CFloat64:
93
0
            return static_cast<const double *>(pSource)[2 * ii];
94
0
        case GDT_TypeCount:
95
0
            break;
96
0
    }
97
0
    return 0;
98
0
}
99
100
static bool IsNoData(double dfVal, double dfNoData)
101
0
{
102
0
    return dfVal == dfNoData || (std::isnan(dfVal) && std::isnan(dfNoData));
103
0
}
104
105
static CPLErr FetchDoubleArg(CSLConstList papszArgs, const char *pszName,
106
                             double *pdfX, double *pdfDefault = nullptr)
107
0
{
108
0
    const char *pszVal = CSLFetchNameValue(papszArgs, pszName);
109
110
0
    if (pszVal == nullptr)
111
0
    {
112
0
        if (pdfDefault == nullptr)
113
0
        {
114
0
            CPLError(CE_Failure, CPLE_AppDefined,
115
0
                     "Missing pixel function argument: %s", pszName);
116
0
            return CE_Failure;
117
0
        }
118
0
        else
119
0
        {
120
0
            *pdfX = *pdfDefault;
121
0
            return CE_None;
122
0
        }
123
0
    }
124
125
0
    char *pszEnd = nullptr;
126
0
    *pdfX = std::strtod(pszVal, &pszEnd);
127
0
    if (pszEnd == pszVal)
128
0
    {
129
0
        CPLError(CE_Failure, CPLE_AppDefined,
130
0
                 "Failed to parse pixel function argument: %s", pszName);
131
0
        return CE_Failure;
132
0
    }
133
134
0
    return CE_None;
135
0
}
136
137
static CPLErr RealPixelFunc(void **papoSources, int nSources, void *pData,
138
                            int nXSize, int nYSize, GDALDataType eSrcType,
139
                            GDALDataType eBufType, int nPixelSpace,
140
                            int nLineSpace)
141
0
{
142
    /* ---- Init ---- */
143
0
    if (nSources != 1)
144
0
        return CE_Failure;
145
146
0
    const int nPixelSpaceSrc = GDALGetDataTypeSizeBytes(eSrcType);
147
0
    const size_t nLineSpaceSrc = static_cast<size_t>(nPixelSpaceSrc) * nXSize;
148
149
    /* ---- Set pixels ---- */
150
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
151
0
    {
152
0
        GDALCopyWords(static_cast<GByte *>(papoSources[0]) +
153
0
                          nLineSpaceSrc * iLine,
154
0
                      eSrcType, nPixelSpaceSrc,
155
0
                      static_cast<GByte *>(pData) +
156
0
                          static_cast<GSpacing>(nLineSpace) * iLine,
157
0
                      eBufType, nPixelSpace, nXSize);
158
0
    }
159
160
    /* ---- Return success ---- */
161
0
    return CE_None;
162
0
}  // RealPixelFunc
163
164
static CPLErr ImagPixelFunc(void **papoSources, int nSources, void *pData,
165
                            int nXSize, int nYSize, GDALDataType eSrcType,
166
                            GDALDataType eBufType, int nPixelSpace,
167
                            int nLineSpace)
168
0
{
169
    /* ---- Init ---- */
170
0
    if (nSources != 1)
171
0
        return CE_Failure;
172
173
0
    if (GDALDataTypeIsComplex(eSrcType))
174
0
    {
175
0
        const GDALDataType eSrcBaseType = GDALGetNonComplexDataType(eSrcType);
176
0
        const int nPixelSpaceSrc = GDALGetDataTypeSizeBytes(eSrcType);
177
0
        const size_t nLineSpaceSrc =
178
0
            static_cast<size_t>(nPixelSpaceSrc) * nXSize;
179
180
0
        const void *const pImag = static_cast<GByte *>(papoSources[0]) +
181
0
                                  GDALGetDataTypeSizeBytes(eSrcType) / 2;
182
183
        /* ---- Set pixels ---- */
184
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
185
0
        {
186
0
            GDALCopyWords(static_cast<const GByte *>(pImag) +
187
0
                              nLineSpaceSrc * iLine,
188
0
                          eSrcBaseType, nPixelSpaceSrc,
189
0
                          static_cast<GByte *>(pData) +
190
0
                              static_cast<GSpacing>(nLineSpace) * iLine,
191
0
                          eBufType, nPixelSpace, nXSize);
192
0
        }
193
0
    }
194
0
    else
195
0
    {
196
0
        const double dfImag = 0;
197
198
        /* ---- Set pixels ---- */
199
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
200
0
        {
201
            // Always copy from the same location.
202
0
            GDALCopyWords(&dfImag, eSrcType, 0,
203
0
                          static_cast<GByte *>(pData) +
204
0
                              static_cast<GSpacing>(nLineSpace) * iLine,
205
0
                          eBufType, nPixelSpace, nXSize);
206
0
        }
207
0
    }
208
209
    /* ---- Return success ---- */
210
0
    return CE_None;
211
0
}  // ImagPixelFunc
212
213
static CPLErr ComplexPixelFunc(void **papoSources, int nSources, void *pData,
214
                               int nXSize, int nYSize, GDALDataType eSrcType,
215
                               GDALDataType eBufType, int nPixelSpace,
216
                               int nLineSpace)
217
0
{
218
    /* ---- Init ---- */
219
0
    if (nSources != 2)
220
0
        return CE_Failure;
221
222
0
    const void *const pReal = papoSources[0];
223
0
    const void *const pImag = papoSources[1];
224
225
    /* ---- Set pixels ---- */
226
0
    size_t ii = 0;
227
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
228
0
    {
229
0
        for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
230
0
        {
231
            // Source raster pixels may be obtained with GetSrcVal macro.
232
0
            const double adfPixVal[2] = {
233
0
                GetSrcVal(pReal, eSrcType, ii),  // re
234
0
                GetSrcVal(pImag, eSrcType, ii)   // im
235
0
            };
236
237
0
            GDALCopyWords(adfPixVal, GDT_CFloat64, 0,
238
0
                          static_cast<GByte *>(pData) +
239
0
                              static_cast<GSpacing>(nLineSpace) * iLine +
240
0
                              iCol * nPixelSpace,
241
0
                          eBufType, nPixelSpace, 1);
242
0
        }
243
0
    }
244
245
    /* ---- Return success ---- */
246
0
    return CE_None;
247
0
}  // ComplexPixelFunc
248
249
typedef enum
250
{
251
    GAT_amplitude,
252
    GAT_intensity,
253
    GAT_dB
254
} PolarAmplitudeType;
255
256
static const char pszPolarPixelFuncMetadata[] =
257
    "<PixelFunctionArgumentsList>"
258
    "   <Argument name='amplitude_type' description='Amplitude Type' "
259
    "type='string-select' default='AMPLITUDE'>"
260
    "       <Value>INTENSITY</Value>"
261
    "       <Value>dB</Value>"
262
    "       <Value>AMPLITUDE</Value>"
263
    "   </Argument>"
264
    "</PixelFunctionArgumentsList>";
265
266
static CPLErr PolarPixelFunc(void **papoSources, int nSources, void *pData,
267
                             int nXSize, int nYSize, GDALDataType eSrcType,
268
                             GDALDataType eBufType, int nPixelSpace,
269
                             int nLineSpace, CSLConstList papszArgs)
270
0
{
271
    /* ---- Init ---- */
272
0
    if (nSources != 2)
273
0
        return CE_Failure;
274
275
0
    const char pszName[] = "amplitude_type";
276
0
    const char *pszVal = CSLFetchNameValue(papszArgs, pszName);
277
0
    PolarAmplitudeType amplitudeType = GAT_amplitude;
278
0
    if (pszVal != nullptr)
279
0
    {
280
0
        if (strcmp(pszVal, "INTENSITY") == 0)
281
0
            amplitudeType = GAT_intensity;
282
0
        else if (strcmp(pszVal, "dB") == 0)
283
0
            amplitudeType = GAT_dB;
284
0
        else if (strcmp(pszVal, "AMPLITUDE") != 0)
285
0
        {
286
0
            CPLError(CE_Failure, CPLE_AppDefined,
287
0
                     "Invalid value for pixel function argument '%s': %s",
288
0
                     pszName, pszVal);
289
0
            return CE_Failure;
290
0
        }
291
0
    }
292
293
0
    const void *const pAmp = papoSources[0];
294
0
    const void *const pPhase = papoSources[1];
295
296
    /* ---- Set pixels ---- */
297
0
    size_t ii = 0;
298
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
299
0
    {
300
0
        for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
301
0
        {
302
            // Source raster pixels may be obtained with GetSrcVal macro.
303
0
            double dfAmp = GetSrcVal(pAmp, eSrcType, ii);
304
0
            switch (amplitudeType)
305
0
            {
306
0
                case GAT_intensity:
307
                    // clip to zero
308
0
                    dfAmp = dfAmp <= 0 ? 0 : std::sqrt(dfAmp);
309
0
                    break;
310
0
                case GAT_dB:
311
0
                    dfAmp = dfAmp <= 0
312
0
                                ? -std::numeric_limits<double>::infinity()
313
0
                                : pow(10, dfAmp / 20.);
314
0
                    break;
315
0
                case GAT_amplitude:
316
0
                    break;
317
0
            }
318
0
            const double dfPhase = GetSrcVal(pPhase, eSrcType, ii);
319
0
            const double adfPixVal[2] = {
320
0
                dfAmp * std::cos(dfPhase),  // re
321
0
                dfAmp * std::sin(dfPhase)   // im
322
0
            };
323
324
0
            GDALCopyWords(adfPixVal, GDT_CFloat64, 0,
325
0
                          static_cast<GByte *>(pData) +
326
0
                              static_cast<GSpacing>(nLineSpace) * iLine +
327
0
                              iCol * nPixelSpace,
328
0
                          eBufType, nPixelSpace, 1);
329
0
        }
330
0
    }
331
332
    /* ---- Return success ---- */
333
0
    return CE_None;
334
0
}  // PolarPixelFunc
335
336
static CPLErr ModulePixelFunc(void **papoSources, int nSources, void *pData,
337
                              int nXSize, int nYSize, GDALDataType eSrcType,
338
                              GDALDataType eBufType, int nPixelSpace,
339
                              int nLineSpace)
340
0
{
341
    /* ---- Init ---- */
342
0
    if (nSources != 1)
343
0
        return CE_Failure;
344
345
0
    if (GDALDataTypeIsComplex(eSrcType))
346
0
    {
347
0
        const void *pReal = papoSources[0];
348
0
        const void *pImag = static_cast<GByte *>(papoSources[0]) +
349
0
                            GDALGetDataTypeSizeBytes(eSrcType) / 2;
350
351
        /* ---- Set pixels ---- */
352
0
        size_t ii = 0;
353
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
354
0
        {
355
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
356
0
            {
357
                // Source raster pixels may be obtained with GetSrcVal macro.
358
0
                const double dfReal = GetSrcVal(pReal, eSrcType, ii);
359
0
                const double dfImag = GetSrcVal(pImag, eSrcType, ii);
360
361
0
                const double dfPixVal = sqrt(dfReal * dfReal + dfImag * dfImag);
362
363
0
                GDALCopyWords(&dfPixVal, GDT_Float64, 0,
364
0
                              static_cast<GByte *>(pData) +
365
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
366
0
                                  iCol * nPixelSpace,
367
0
                              eBufType, nPixelSpace, 1);
368
0
            }
369
0
        }
370
0
    }
371
0
    else
372
0
    {
373
        /* ---- Set pixels ---- */
374
0
        size_t ii = 0;
375
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
376
0
        {
377
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
378
0
            {
379
                // Source raster pixels may be obtained with GetSrcVal macro.
380
0
                const double dfPixVal =
381
0
                    fabs(GetSrcVal(papoSources[0], eSrcType, ii));
382
383
0
                GDALCopyWords(&dfPixVal, GDT_Float64, 0,
384
0
                              static_cast<GByte *>(pData) +
385
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
386
0
                                  iCol * nPixelSpace,
387
0
                              eBufType, nPixelSpace, 1);
388
0
            }
389
0
        }
390
0
    }
391
392
    /* ---- Return success ---- */
393
0
    return CE_None;
394
0
}  // ModulePixelFunc
395
396
static CPLErr PhasePixelFunc(void **papoSources, int nSources, void *pData,
397
                             int nXSize, int nYSize, GDALDataType eSrcType,
398
                             GDALDataType eBufType, int nPixelSpace,
399
                             int nLineSpace)
400
0
{
401
    /* ---- Init ---- */
402
0
    if (nSources != 1)
403
0
        return CE_Failure;
404
405
0
    if (GDALDataTypeIsComplex(eSrcType))
406
0
    {
407
0
        const void *const pReal = papoSources[0];
408
0
        const void *const pImag = static_cast<GByte *>(papoSources[0]) +
409
0
                                  GDALGetDataTypeSizeBytes(eSrcType) / 2;
410
411
        /* ---- Set pixels ---- */
412
0
        size_t ii = 0;
413
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
414
0
        {
415
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
416
0
            {
417
                // Source raster pixels may be obtained with GetSrcVal macro.
418
0
                const double dfReal = GetSrcVal(pReal, eSrcType, ii);
419
0
                const double dfImag = GetSrcVal(pImag, eSrcType, ii);
420
421
0
                const double dfPixVal = atan2(dfImag, dfReal);
422
423
0
                GDALCopyWords(&dfPixVal, GDT_Float64, 0,
424
0
                              static_cast<GByte *>(pData) +
425
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
426
0
                                  iCol * nPixelSpace,
427
0
                              eBufType, nPixelSpace, 1);
428
0
            }
429
0
        }
430
0
    }
431
0
    else if (GDALDataTypeIsInteger(eSrcType) && !GDALDataTypeIsSigned(eSrcType))
432
0
    {
433
0
        constexpr double dfZero = 0;
434
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
435
0
        {
436
0
            GDALCopyWords(&dfZero, GDT_Float64, 0,
437
0
                          static_cast<GByte *>(pData) +
438
0
                              static_cast<GSpacing>(nLineSpace) * iLine,
439
0
                          eBufType, nPixelSpace, nXSize);
440
0
        }
441
0
    }
442
0
    else
443
0
    {
444
        /* ---- Set pixels ---- */
445
0
        size_t ii = 0;
446
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
447
0
        {
448
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
449
0
            {
450
0
                const void *const pReal = papoSources[0];
451
452
                // Source raster pixels may be obtained with GetSrcVal macro.
453
0
                const double dfReal = GetSrcVal(pReal, eSrcType, ii);
454
0
                const double dfPixVal = (dfReal < 0) ? M_PI : 0.0;
455
456
0
                GDALCopyWords(&dfPixVal, GDT_Float64, 0,
457
0
                              static_cast<GByte *>(pData) +
458
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
459
0
                                  iCol * nPixelSpace,
460
0
                              eBufType, nPixelSpace, 1);
461
0
            }
462
0
        }
463
0
    }
464
465
    /* ---- Return success ---- */
466
0
    return CE_None;
467
0
}  // PhasePixelFunc
468
469
static CPLErr ConjPixelFunc(void **papoSources, int nSources, void *pData,
470
                            int nXSize, int nYSize, GDALDataType eSrcType,
471
                            GDALDataType eBufType, int nPixelSpace,
472
                            int nLineSpace)
473
0
{
474
    /* ---- Init ---- */
475
0
    if (nSources != 1)
476
0
        return CE_Failure;
477
478
0
    if (GDALDataTypeIsComplex(eSrcType) && GDALDataTypeIsComplex(eBufType))
479
0
    {
480
0
        const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;
481
0
        const void *const pReal = papoSources[0];
482
0
        const void *const pImag =
483
0
            static_cast<GByte *>(papoSources[0]) + nOffset;
484
485
        /* ---- Set pixels ---- */
486
0
        size_t ii = 0;
487
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
488
0
        {
489
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
490
0
            {
491
                // Source raster pixels may be obtained with GetSrcVal macro.
492
0
                const double adfPixVal[2] = {
493
0
                    +GetSrcVal(pReal, eSrcType, ii),  // re
494
0
                    -GetSrcVal(pImag, eSrcType, ii)   // im
495
0
                };
496
497
0
                GDALCopyWords(adfPixVal, GDT_CFloat64, 0,
498
0
                              static_cast<GByte *>(pData) +
499
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
500
0
                                  iCol * nPixelSpace,
501
0
                              eBufType, nPixelSpace, 1);
502
0
            }
503
0
        }
504
0
    }
505
0
    else
506
0
    {
507
        // No complex data type.
508
0
        return RealPixelFunc(papoSources, nSources, pData, nXSize, nYSize,
509
0
                             eSrcType, eBufType, nPixelSpace, nLineSpace);
510
0
    }
511
512
    /* ---- Return success ---- */
513
0
    return CE_None;
514
0
}  // ConjPixelFunc
515
516
#ifdef USE_SSE2
517
518
/************************************************************************/
519
/*                        OptimizedSumToFloat_SSE2()                    */
520
/************************************************************************/
521
522
template <typename Tsrc>
523
static void OptimizedSumToFloat_SSE2(double dfK, void *pOutBuffer,
524
                                     int nLineSpace, int nXSize, int nYSize,
525
                                     int nSources,
526
                                     const void *const *papoSources)
527
0
{
528
0
    const XMMReg4Float cst = XMMReg4Float::Set1(static_cast<float>(dfK));
529
530
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
531
0
    {
532
0
        float *CPL_RESTRICT const pDest = reinterpret_cast<float *>(
533
0
            static_cast<GByte *>(pOutBuffer) +
534
0
            static_cast<GSpacing>(nLineSpace) * iLine);
535
0
        const size_t iOffsetLine = static_cast<size_t>(iLine) * nXSize;
536
537
0
        constexpr int VALUES_PER_REG = 4;
538
0
        constexpr int UNROLLING = 4 * VALUES_PER_REG;
539
0
        int iCol = 0;
540
0
        for (; iCol < nXSize - (UNROLLING - 1); iCol += UNROLLING)
541
0
        {
542
0
            XMMReg4Float d0(cst);
543
0
            XMMReg4Float d1(cst);
544
0
            XMMReg4Float d2(cst);
545
0
            XMMReg4Float d3(cst);
546
0
            for (int iSrc = 0; iSrc < nSources; ++iSrc)
547
0
            {
548
0
                XMMReg4Float t0, t1, t2, t3;
549
0
                XMMReg4Float::Load16Val(
550
0
                    static_cast<const Tsrc * CPL_RESTRICT>(papoSources[iSrc]) +
551
0
                        iOffsetLine + iCol,
552
0
                    t0, t1, t2, t3);
553
0
                d0 += t0;
554
0
                d1 += t1;
555
0
                d2 += t2;
556
0
                d3 += t3;
557
0
            }
558
0
            d0.Store4Val(pDest + iCol + VALUES_PER_REG * 0);
559
0
            d1.Store4Val(pDest + iCol + VALUES_PER_REG * 1);
560
0
            d2.Store4Val(pDest + iCol + VALUES_PER_REG * 2);
561
0
            d3.Store4Val(pDest + iCol + VALUES_PER_REG * 3);
562
0
        }
563
564
0
        for (; iCol < nXSize; iCol++)
565
0
        {
566
0
            float d = static_cast<float>(dfK);
567
0
            for (int iSrc = 0; iSrc < nSources; ++iSrc)
568
0
            {
569
0
                d += static_cast<const Tsrc * CPL_RESTRICT>(
570
0
                    papoSources[iSrc])[iOffsetLine + iCol];
571
0
            }
572
0
            pDest[iCol] = d;
573
0
        }
574
0
    }
575
0
}
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumToFloat_SSE2<unsigned char>(double, void*, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumToFloat_SSE2<unsigned short>(double, void*, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumToFloat_SSE2<short>(double, void*, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumToFloat_SSE2<int>(double, void*, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumToFloat_SSE2<float>(double, void*, int, int, int, int, void const* const*)
576
577
/************************************************************************/
578
/*                       OptimizedSumToDouble_SSE2()                    */
579
/************************************************************************/
580
581
template <typename Tsrc>
582
static void OptimizedSumToDouble_SSE2(double dfK, void *pOutBuffer,
583
                                      int nLineSpace, int nXSize, int nYSize,
584
                                      int nSources,
585
                                      const void *const *papoSources)
586
0
{
587
0
    const XMMReg4Double cst = XMMReg4Double::Set1(dfK);
588
589
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
590
0
    {
591
0
        double *CPL_RESTRICT const pDest = reinterpret_cast<double *>(
592
0
            static_cast<GByte *>(pOutBuffer) +
593
0
            static_cast<GSpacing>(nLineSpace) * iLine);
594
0
        const size_t iOffsetLine = static_cast<size_t>(iLine) * nXSize;
595
596
0
        constexpr int VALUES_PER_REG = 4;
597
0
        constexpr int UNROLLING = 2 * VALUES_PER_REG;
598
0
        int iCol = 0;
599
0
        for (; iCol < nXSize - (UNROLLING - 1); iCol += UNROLLING)
600
0
        {
601
0
            XMMReg4Double d0(cst);
602
0
            XMMReg4Double d1(cst);
603
0
            for (int iSrc = 0; iSrc < nSources; ++iSrc)
604
0
            {
605
0
                XMMReg4Double t0, t1;
606
0
                XMMReg4Double::Load8Val(
607
0
                    static_cast<const Tsrc * CPL_RESTRICT>(papoSources[iSrc]) +
608
0
                        iOffsetLine + iCol,
609
0
                    t0, t1);
610
0
                d0 += t0;
611
0
                d1 += t1;
612
0
            }
613
0
            d0.Store4Val(pDest + iCol + VALUES_PER_REG * 0);
614
0
            d1.Store4Val(pDest + iCol + VALUES_PER_REG * 1);
615
0
        }
616
617
0
        for (; iCol < nXSize; iCol++)
618
0
        {
619
0
            double d = dfK;
620
0
            for (int iSrc = 0; iSrc < nSources; ++iSrc)
621
0
            {
622
0
                d += static_cast<const Tsrc * CPL_RESTRICT>(
623
0
                    papoSources[iSrc])[iOffsetLine + iCol];
624
0
            }
625
0
            pDest[iCol] = d;
626
0
        }
627
0
    }
628
0
}
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumToDouble_SSE2<unsigned char>(double, void*, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumToDouble_SSE2<unsigned short>(double, void*, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumToDouble_SSE2<short>(double, void*, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumToDouble_SSE2<int>(double, void*, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumToDouble_SSE2<float>(double, void*, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumToDouble_SSE2<double>(double, void*, int, int, int, int, void const* const*)
629
630
/************************************************************************/
631
/*                       OptimizedSumSameType_SSE2()                    */
632
/************************************************************************/
633
634
template <typename T, typename Tsigned, typename Tacc, class SSEWrapper>
635
static void OptimizedSumSameType_SSE2(double dfK, void *pOutBuffer,
636
                                      int nLineSpace, int nXSize, int nYSize,
637
                                      int nSources,
638
                                      const void *const *papoSources)
639
0
{
640
0
    static_assert(std::numeric_limits<T>::is_integer);
641
0
    static_assert(!std::numeric_limits<T>::is_signed);
642
0
    static_assert(std::numeric_limits<Tsigned>::is_integer);
643
0
    static_assert(std::numeric_limits<Tsigned>::is_signed);
644
0
    static_assert(sizeof(T) == sizeof(Tsigned));
645
0
    const T nK = static_cast<T>(dfK);
646
0
    Tsigned nKSigned;
647
0
    memcpy(&nKSigned, &nK, sizeof(T));
648
0
    const __m128i valInit = SSEWrapper::Set1(nKSigned);
649
0
    constexpr int VALUES_PER_REG =
650
0
        static_cast<int>(sizeof(valInit) / sizeof(T));
651
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
652
0
    {
653
0
        T *CPL_RESTRICT const pDest =
654
0
            reinterpret_cast<T *>(static_cast<GByte *>(pOutBuffer) +
655
0
                                  static_cast<GSpacing>(nLineSpace) * iLine);
656
0
        const size_t iOffsetLine = static_cast<size_t>(iLine) * nXSize;
657
0
        int iCol = 0;
658
0
        for (; iCol < nXSize - (4 * VALUES_PER_REG - 1);
659
0
             iCol += 4 * VALUES_PER_REG)
660
0
        {
661
0
            __m128i reg0 = valInit;
662
0
            __m128i reg1 = valInit;
663
0
            __m128i reg2 = valInit;
664
0
            __m128i reg3 = valInit;
665
0
            for (int iSrc = 0; iSrc < nSources; ++iSrc)
666
0
            {
667
0
                reg0 = SSEWrapper::AddSaturate(
668
0
                    reg0,
669
0
                    _mm_loadu_si128(reinterpret_cast<const __m128i *>(
670
0
                        static_cast<const T * CPL_RESTRICT>(papoSources[iSrc]) +
671
0
                        iOffsetLine + iCol)));
672
0
                reg1 = SSEWrapper::AddSaturate(
673
0
                    reg1,
674
0
                    _mm_loadu_si128(reinterpret_cast<const __m128i *>(
675
0
                        static_cast<const T * CPL_RESTRICT>(papoSources[iSrc]) +
676
0
                        iOffsetLine + iCol + VALUES_PER_REG)));
677
0
                reg2 = SSEWrapper::AddSaturate(
678
0
                    reg2,
679
0
                    _mm_loadu_si128(reinterpret_cast<const __m128i *>(
680
0
                        static_cast<const T * CPL_RESTRICT>(papoSources[iSrc]) +
681
0
                        iOffsetLine + iCol + 2 * VALUES_PER_REG)));
682
0
                reg3 = SSEWrapper::AddSaturate(
683
0
                    reg3,
684
0
                    _mm_loadu_si128(reinterpret_cast<const __m128i *>(
685
0
                        static_cast<const T * CPL_RESTRICT>(papoSources[iSrc]) +
686
0
                        iOffsetLine + iCol + 3 * VALUES_PER_REG)));
687
0
            }
688
0
            _mm_storeu_si128(reinterpret_cast<__m128i *>(pDest + iCol), reg0);
689
0
            _mm_storeu_si128(
690
0
                reinterpret_cast<__m128i *>(pDest + iCol + VALUES_PER_REG),
691
0
                reg1);
692
0
            _mm_storeu_si128(
693
0
                reinterpret_cast<__m128i *>(pDest + iCol + 2 * VALUES_PER_REG),
694
0
                reg2);
695
0
            _mm_storeu_si128(
696
0
                reinterpret_cast<__m128i *>(pDest + iCol + 3 * VALUES_PER_REG),
697
0
                reg3);
698
0
        }
699
0
        for (; iCol < nXSize; ++iCol)
700
0
        {
701
0
            Tacc nAcc = nK;
702
0
            for (int iSrc = 0; iSrc < nSources; ++iSrc)
703
0
            {
704
0
                nAcc = std::min<Tacc>(
705
0
                    nAcc + static_cast<const T * CPL_RESTRICT>(
706
0
                               papoSources[iSrc])[iOffsetLine + iCol],
707
0
                    std::numeric_limits<T>::max());
708
0
            }
709
0
            pDest[iCol] = static_cast<T>(nAcc);
710
0
        }
711
0
    }
712
0
}
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumSameType_SSE2<unsigned char, signed char, unsigned int, SumPixelFunc(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)::SSEWrapper>(double, void*, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumSameType_SSE2<unsigned short, short, unsigned int, SumPixelFunc(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)::SSEWrapper>(double, void*, int, int, int, int, void const* const*)
713
#endif  // USE_SSE2
714
715
/************************************************************************/
716
/*                       OptimizedSumPackedOutput()                     */
717
/************************************************************************/
718
719
template <typename Tsrc, typename Tdest>
720
static void OptimizedSumPackedOutput(double dfK, void *pOutBuffer,
721
                                     int nLineSpace, int nXSize, int nYSize,
722
                                     int nSources,
723
                                     const void *const *papoSources)
724
0
{
725
0
#ifdef USE_SSE2
726
    if constexpr (std::is_same_v<Tdest, float> && !std::is_same_v<Tsrc, double>)
727
0
    {
728
0
        OptimizedSumToFloat_SSE2<Tsrc>(dfK, pOutBuffer, nLineSpace, nXSize,
729
0
                                       nYSize, nSources, papoSources);
730
    }
731
    else if constexpr (std::is_same_v<Tdest, double>)
732
0
    {
733
0
        OptimizedSumToDouble_SSE2<Tsrc>(dfK, pOutBuffer, nLineSpace, nXSize,
734
0
                                        nYSize, nSources, papoSources);
735
    }
736
    else
737
#endif  // USE_SSE2
738
0
    {
739
0
        const Tdest nCst = static_cast<Tdest>(dfK);
740
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
741
0
        {
742
0
            Tdest *CPL_RESTRICT const pDest = reinterpret_cast<Tdest *>(
743
0
                static_cast<GByte *>(pOutBuffer) +
744
0
                static_cast<GSpacing>(nLineSpace) * iLine);
745
0
            const size_t iOffsetLine = static_cast<size_t>(iLine) * nXSize;
746
747
0
#define LOAD_SRCVAL(iSrc_, j_)                                                 \
748
0
    static_cast<Tdest>(static_cast<const Tsrc * CPL_RESTRICT>(                 \
749
0
        papoSources[(iSrc_)])[iOffsetLine + iCol + (j_)])
750
751
0
            constexpr int UNROLLING = 4;
752
0
            int iCol = 0;
753
0
            for (; iCol < nXSize - (UNROLLING - 1); iCol += UNROLLING)
754
0
            {
755
0
                Tdest d[4] = {nCst, nCst, nCst, nCst};
756
0
                for (int iSrc = 0; iSrc < nSources; ++iSrc)
757
0
                {
758
0
                    d[0] += LOAD_SRCVAL(iSrc, 0);
759
0
                    d[1] += LOAD_SRCVAL(iSrc, 1);
760
0
                    d[2] += LOAD_SRCVAL(iSrc, 2);
761
0
                    d[3] += LOAD_SRCVAL(iSrc, 3);
762
0
                }
763
0
                pDest[iCol + 0] = d[0];
764
0
                pDest[iCol + 1] = d[1];
765
0
                pDest[iCol + 2] = d[2];
766
0
                pDest[iCol + 3] = d[3];
767
0
            }
768
0
            for (; iCol < nXSize; iCol++)
769
0
            {
770
0
                Tdest d0 = nCst;
771
0
                for (int iSrc = 0; iSrc < nSources; ++iSrc)
772
0
                {
773
0
                    d0 += LOAD_SRCVAL(iSrc, 0);
774
0
                }
775
0
                pDest[iCol] = d0;
776
0
            }
777
0
#undef LOAD_SRCVAL
778
0
        }
779
0
    }
780
0
}
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumPackedOutput<unsigned char, float>(double, void*, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumPackedOutput<unsigned short, float>(double, void*, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumPackedOutput<short, float>(double, void*, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumPackedOutput<int, float>(double, void*, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumPackedOutput<float, float>(double, void*, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumPackedOutput<double, float>(double, void*, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumPackedOutput<unsigned char, double>(double, void*, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumPackedOutput<unsigned short, double>(double, void*, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumPackedOutput<short, double>(double, void*, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumPackedOutput<int, double>(double, void*, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumPackedOutput<float, double>(double, void*, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumPackedOutput<double, double>(double, void*, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumPackedOutput<unsigned char, int>(double, void*, int, int, int, int, void const* const*)
781
782
/************************************************************************/
783
/*                       OptimizedSumPackedOutput()                     */
784
/************************************************************************/
785
786
template <typename Tdest>
787
static bool OptimizedSumPackedOutput(GDALDataType eSrcType, double dfK,
788
                                     void *pOutBuffer, int nLineSpace,
789
                                     int nXSize, int nYSize, int nSources,
790
                                     const void *const *papoSources)
791
0
{
792
0
    switch (eSrcType)
793
0
    {
794
0
        case GDT_Byte:
795
0
            OptimizedSumPackedOutput<uint8_t, Tdest>(dfK, pOutBuffer,
796
0
                                                     nLineSpace, nXSize, nYSize,
797
0
                                                     nSources, papoSources);
798
0
            return true;
799
800
0
        case GDT_UInt16:
801
0
            OptimizedSumPackedOutput<uint16_t, Tdest>(
802
0
                dfK, pOutBuffer, nLineSpace, nXSize, nYSize, nSources,
803
0
                papoSources);
804
0
            return true;
805
806
0
        case GDT_Int16:
807
0
            OptimizedSumPackedOutput<int16_t, Tdest>(dfK, pOutBuffer,
808
0
                                                     nLineSpace, nXSize, nYSize,
809
0
                                                     nSources, papoSources);
810
0
            return true;
811
812
0
        case GDT_Int32:
813
0
            OptimizedSumPackedOutput<int32_t, Tdest>(dfK, pOutBuffer,
814
0
                                                     nLineSpace, nXSize, nYSize,
815
0
                                                     nSources, papoSources);
816
0
            return true;
817
818
0
        case GDT_Float32:
819
0
            OptimizedSumPackedOutput<float, Tdest>(dfK, pOutBuffer, nLineSpace,
820
0
                                                   nXSize, nYSize, nSources,
821
0
                                                   papoSources);
822
0
            return true;
823
824
0
        case GDT_Float64:
825
0
            OptimizedSumPackedOutput<double, Tdest>(dfK, pOutBuffer, nLineSpace,
826
0
                                                    nXSize, nYSize, nSources,
827
0
                                                    papoSources);
828
0
            return true;
829
830
0
        default:
831
0
            break;
832
0
    }
833
0
    return false;
834
0
}
Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumPackedOutput<float>(GDALDataType, double, void*, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumPackedOutput<double>(GDALDataType, double, void*, int, int, int, int, void const* const*)
835
836
/************************************************************************/
837
/*                    OptimizedSumThroughLargerType()                   */
838
/************************************************************************/
839
840
namespace
841
{
842
template <typename Tsrc, typename Tdest, typename Enable = void>
843
struct TintermediateS
844
{
845
    using type = double;
846
};
847
848
template <typename Tsrc, typename Tdest>
849
struct TintermediateS<
850
    Tsrc, Tdest,
851
    std::enable_if_t<
852
        (std::is_same_v<Tsrc, uint8_t> || std::is_same_v<Tsrc, int16_t> ||
853
         std::is_same_v<Tsrc, uint16_t>)&&(std::is_same_v<Tdest, uint8_t> ||
854
                                           std::is_same_v<Tdest, int16_t> ||
855
                                           std::is_same_v<Tdest, uint16_t>),
856
        bool>>
857
{
858
    using type = int32_t;
859
};
860
861
}  // namespace
862
863
template <typename Tsrc, typename Tdest>
864
static bool OptimizedSumThroughLargerType(double dfK, void *pOutBuffer,
865
                                          int nPixelSpace, int nLineSpace,
866
                                          int nXSize, int nYSize, int nSources,
867
                                          const void *const *papoSources)
868
0
{
869
0
    using Tintermediate = typename TintermediateS<Tsrc, Tdest>::type;
870
0
    const Tintermediate k = static_cast<Tintermediate>(dfK);
871
872
0
    size_t ii = 0;
873
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
874
0
    {
875
0
        GByte *CPL_RESTRICT pDest = static_cast<GByte *>(pOutBuffer) +
876
0
                                    static_cast<GSpacing>(nLineSpace) * iLine;
877
878
0
        constexpr int UNROLLING = 4;
879
0
        int iCol = 0;
880
0
        for (; iCol < nXSize - (UNROLLING - 1);
881
0
             iCol += UNROLLING, ii += UNROLLING)
882
0
        {
883
0
            Tintermediate aSum[4] = {k, k, k, k};
884
885
0
            for (int iSrc = 0; iSrc < nSources; ++iSrc)
886
0
            {
887
0
                aSum[0] += static_cast<const Tsrc *>(papoSources[iSrc])[ii + 0];
888
0
                aSum[1] += static_cast<const Tsrc *>(papoSources[iSrc])[ii + 1];
889
0
                aSum[2] += static_cast<const Tsrc *>(papoSources[iSrc])[ii + 2];
890
0
                aSum[3] += static_cast<const Tsrc *>(papoSources[iSrc])[ii + 3];
891
0
            }
892
893
0
            GDALCopyWord(aSum[0], *reinterpret_cast<Tdest *>(pDest));
894
0
            pDest += nPixelSpace;
895
0
            GDALCopyWord(aSum[1], *reinterpret_cast<Tdest *>(pDest));
896
0
            pDest += nPixelSpace;
897
0
            GDALCopyWord(aSum[2], *reinterpret_cast<Tdest *>(pDest));
898
0
            pDest += nPixelSpace;
899
0
            GDALCopyWord(aSum[3], *reinterpret_cast<Tdest *>(pDest));
900
0
            pDest += nPixelSpace;
901
0
        }
902
0
        for (; iCol < nXSize; ++iCol, ++ii, pDest += nPixelSpace)
903
0
        {
904
0
            Tintermediate sum = k;
905
0
            for (int iSrc = 0; iSrc < nSources; ++iSrc)
906
0
            {
907
0
                sum += static_cast<const Tsrc *>(papoSources[iSrc])[ii];
908
0
            }
909
910
0
            auto pDst = reinterpret_cast<Tdest *>(pDest);
911
0
            GDALCopyWord(sum, *pDst);
912
0
        }
913
0
    }
914
0
    return true;
915
0
}
Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<unsigned char, unsigned char>(double, void*, int, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<unsigned char, unsigned short>(double, void*, int, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<unsigned char, short>(double, void*, int, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<unsigned char, int>(double, void*, int, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<unsigned short, unsigned char>(double, void*, int, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<unsigned short, unsigned short>(double, void*, int, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<unsigned short, short>(double, void*, int, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<unsigned short, int>(double, void*, int, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<short, unsigned char>(double, void*, int, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<short, unsigned short>(double, void*, int, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<short, short>(double, void*, int, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<short, int>(double, void*, int, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<int, unsigned char>(double, void*, int, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<int, unsigned short>(double, void*, int, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<int, short>(double, void*, int, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<int, int>(double, void*, int, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<float, unsigned char>(double, void*, int, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<float, unsigned short>(double, void*, int, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<float, short>(double, void*, int, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<float, int>(double, void*, int, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<double, unsigned char>(double, void*, int, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<double, unsigned short>(double, void*, int, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<double, short>(double, void*, int, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<double, int>(double, void*, int, int, int, int, int, void const* const*)
916
917
/************************************************************************/
918
/*                     OptimizedSumThroughLargerType()                  */
919
/************************************************************************/
920
921
template <typename Tsrc>
922
static bool OptimizedSumThroughLargerType(GDALDataType eBufType, double dfK,
923
                                          void *pOutBuffer, int nPixelSpace,
924
                                          int nLineSpace, int nXSize,
925
                                          int nYSize, int nSources,
926
                                          const void *const *papoSources)
927
0
{
928
0
    switch (eBufType)
929
0
    {
930
0
        case GDT_Byte:
931
0
            return OptimizedSumThroughLargerType<Tsrc, uint8_t>(
932
0
                dfK, pOutBuffer, nPixelSpace, nLineSpace, nXSize, nYSize,
933
0
                nSources, papoSources);
934
935
0
        case GDT_UInt16:
936
0
            return OptimizedSumThroughLargerType<Tsrc, uint16_t>(
937
0
                dfK, pOutBuffer, nPixelSpace, nLineSpace, nXSize, nYSize,
938
0
                nSources, papoSources);
939
940
0
        case GDT_Int16:
941
0
            return OptimizedSumThroughLargerType<Tsrc, int16_t>(
942
0
                dfK, pOutBuffer, nPixelSpace, nLineSpace, nXSize, nYSize,
943
0
                nSources, papoSources);
944
945
0
        case GDT_Int32:
946
0
            return OptimizedSumThroughLargerType<Tsrc, int32_t>(
947
0
                dfK, pOutBuffer, nPixelSpace, nLineSpace, nXSize, nYSize,
948
0
                nSources, papoSources);
949
950
        // Float32 and Float64 already covered by OptimizedSum() for packed case
951
0
        default:
952
0
            break;
953
0
    }
954
0
    return false;
955
0
}
Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<unsigned char>(GDALDataType, double, void*, int, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<unsigned short>(GDALDataType, double, void*, int, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<short>(GDALDataType, double, void*, int, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<int>(GDALDataType, double, void*, int, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<float>(GDALDataType, double, void*, int, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<double>(GDALDataType, double, void*, int, int, int, int, int, void const* const*)
956
957
/************************************************************************/
958
/*                    OptimizedSumThroughLargerType()                   */
959
/************************************************************************/
960
961
static bool OptimizedSumThroughLargerType(GDALDataType eSrcType,
962
                                          GDALDataType eBufType, double dfK,
963
                                          void *pOutBuffer, int nPixelSpace,
964
                                          int nLineSpace, int nXSize,
965
                                          int nYSize, int nSources,
966
                                          const void *const *papoSources)
967
0
{
968
0
    switch (eSrcType)
969
0
    {
970
0
        case GDT_Byte:
971
0
            return OptimizedSumThroughLargerType<uint8_t>(
972
0
                eBufType, dfK, pOutBuffer, nPixelSpace, nLineSpace, nXSize,
973
0
                nYSize, nSources, papoSources);
974
975
0
        case GDT_UInt16:
976
0
            return OptimizedSumThroughLargerType<uint16_t>(
977
0
                eBufType, dfK, pOutBuffer, nPixelSpace, nLineSpace, nXSize,
978
0
                nYSize, nSources, papoSources);
979
980
0
        case GDT_Int16:
981
0
            return OptimizedSumThroughLargerType<int16_t>(
982
0
                eBufType, dfK, pOutBuffer, nPixelSpace, nLineSpace, nXSize,
983
0
                nYSize, nSources, papoSources);
984
985
0
        case GDT_Int32:
986
0
            return OptimizedSumThroughLargerType<int32_t>(
987
0
                eBufType, dfK, pOutBuffer, nPixelSpace, nLineSpace, nXSize,
988
0
                nYSize, nSources, papoSources);
989
990
0
        case GDT_Float32:
991
0
            return OptimizedSumThroughLargerType<float>(
992
0
                eBufType, dfK, pOutBuffer, nPixelSpace, nLineSpace, nXSize,
993
0
                nYSize, nSources, papoSources);
994
995
0
        case GDT_Float64:
996
0
            return OptimizedSumThroughLargerType<double>(
997
0
                eBufType, dfK, pOutBuffer, nPixelSpace, nLineSpace, nXSize,
998
0
                nYSize, nSources, papoSources);
999
1000
0
        default:
1001
0
            break;
1002
0
    }
1003
1004
0
    return false;
1005
0
}
1006
1007
/************************************************************************/
1008
/*                            SumPixelFunc()                            */
1009
/************************************************************************/
1010
1011
static const char pszSumPixelFuncMetadata[] =
1012
    "<PixelFunctionArgumentsList>"
1013
    "   <Argument name='k' description='Optional constant term' type='double' "
1014
    "default='0.0' />"
1015
    "   <Argument name='propagateNoData' description='Whether the output value "
1016
    "should be NoData as as soon as one source is NoData' type='boolean' "
1017
    "default='false' />"
1018
    "   <Argument type='builtin' value='NoData' optional='true' />"
1019
    "</PixelFunctionArgumentsList>";
1020
1021
static CPLErr SumPixelFunc(void **papoSources, int nSources, void *pData,
1022
                           int nXSize, int nYSize, GDALDataType eSrcType,
1023
                           GDALDataType eBufType, int nPixelSpace,
1024
                           int nLineSpace, CSLConstList papszArgs)
1025
0
{
1026
    /* ---- Init ---- */
1027
0
    if (nSources < 1)
1028
0
    {
1029
0
        CPLError(CE_Failure, CPLE_AppDefined,
1030
0
                 "sum requires at least one source");
1031
0
        return CE_Failure;
1032
0
    }
1033
1034
0
    double dfK = 0.0;
1035
0
    if (FetchDoubleArg(papszArgs, "k", &dfK, &dfK) != CE_None)
1036
0
        return CE_Failure;
1037
1038
0
    double dfNoData{0};
1039
0
    bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
1040
0
    if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)
1041
0
        return CE_Failure;
1042
1043
0
    const bool bPropagateNoData = CPLTestBool(
1044
0
        CSLFetchNameValueDef(papszArgs, "propagateNoData", "false"));
1045
1046
0
    if (dfNoData == 0 && !bPropagateNoData)
1047
0
        bHasNoData = false;
1048
1049
    /* ---- Set pixels ---- */
1050
0
    if (GDALDataTypeIsComplex(eSrcType))
1051
0
    {
1052
0
        const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;
1053
1054
        /* ---- Set pixels ---- */
1055
0
        size_t ii = 0;
1056
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
1057
0
        {
1058
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
1059
0
            {
1060
0
                double adfSum[2] = {dfK, 0.0};
1061
1062
0
                for (int iSrc = 0; iSrc < nSources; ++iSrc)
1063
0
                {
1064
0
                    const void *const pReal = papoSources[iSrc];
1065
0
                    const void *const pImag =
1066
0
                        static_cast<const GByte *>(pReal) + nOffset;
1067
1068
                    // Source raster pixels may be obtained with GetSrcVal
1069
                    // macro.
1070
0
                    adfSum[0] += GetSrcVal(pReal, eSrcType, ii);
1071
0
                    adfSum[1] += GetSrcVal(pImag, eSrcType, ii);
1072
0
                }
1073
1074
0
                GDALCopyWords(adfSum, GDT_CFloat64, 0,
1075
0
                              static_cast<GByte *>(pData) +
1076
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
1077
0
                                  iCol * nPixelSpace,
1078
0
                              eBufType, nPixelSpace, 1);
1079
0
            }
1080
0
        }
1081
0
    }
1082
0
    else
1083
0
    {
1084
        /* ---- Set pixels ---- */
1085
0
        bool bGeneralCase = true;
1086
0
        if (dfNoData == 0 && !bPropagateNoData)
1087
0
        {
1088
0
#ifdef USE_SSE2
1089
0
            if (eBufType == GDT_Byte && nPixelSpace == sizeof(uint8_t) &&
1090
0
                eSrcType == GDT_Byte &&
1091
0
                dfK >= std::numeric_limits<uint8_t>::min() &&
1092
0
                dfK <= std::numeric_limits<uint8_t>::max() &&
1093
0
                static_cast<int>(dfK) == dfK)
1094
0
            {
1095
0
                bGeneralCase = false;
1096
1097
0
                struct SSEWrapper
1098
0
                {
1099
0
                    inline static __m128i Set1(int8_t x)
1100
0
                    {
1101
0
                        return _mm_set1_epi8(x);
1102
0
                    }
1103
1104
0
                    inline static __m128i AddSaturate(__m128i x, __m128i y)
1105
0
                    {
1106
0
                        return _mm_adds_epu8(x, y);
1107
0
                    }
1108
0
                };
1109
1110
0
                OptimizedSumSameType_SSE2<uint8_t, int8_t, uint32_t,
1111
0
                                          SSEWrapper>(dfK, pData, nLineSpace,
1112
0
                                                      nXSize, nYSize, nSources,
1113
0
                                                      papoSources);
1114
0
            }
1115
0
            else if (eBufType == GDT_UInt16 &&
1116
0
                     nPixelSpace == sizeof(uint16_t) &&
1117
0
                     eSrcType == GDT_UInt16 &&
1118
0
                     dfK >= std::numeric_limits<uint16_t>::min() &&
1119
0
                     dfK <= std::numeric_limits<uint16_t>::max() &&
1120
0
                     static_cast<int>(dfK) == dfK)
1121
0
            {
1122
0
                bGeneralCase = false;
1123
1124
0
                struct SSEWrapper
1125
0
                {
1126
0
                    inline static __m128i Set1(int16_t x)
1127
0
                    {
1128
0
                        return _mm_set1_epi16(x);
1129
0
                    }
1130
1131
0
                    inline static __m128i AddSaturate(__m128i x, __m128i y)
1132
0
                    {
1133
0
                        return _mm_adds_epu16(x, y);
1134
0
                    }
1135
0
                };
1136
1137
0
                OptimizedSumSameType_SSE2<uint16_t, int16_t, uint32_t,
1138
0
                                          SSEWrapper>(dfK, pData, nLineSpace,
1139
0
                                                      nXSize, nYSize, nSources,
1140
0
                                                      papoSources);
1141
0
            }
1142
0
            else
1143
0
#endif
1144
0
                if (eBufType == GDT_Float32 && nPixelSpace == sizeof(float))
1145
0
            {
1146
0
                bGeneralCase = !OptimizedSumPackedOutput<float>(
1147
0
                    eSrcType, dfK, pData, nLineSpace, nXSize, nYSize, nSources,
1148
0
                    papoSources);
1149
0
            }
1150
0
            else if (eBufType == GDT_Float64 && nPixelSpace == sizeof(double))
1151
0
            {
1152
0
                bGeneralCase = !OptimizedSumPackedOutput<double>(
1153
0
                    eSrcType, dfK, pData, nLineSpace, nXSize, nYSize, nSources,
1154
0
                    papoSources);
1155
0
            }
1156
0
            else if (
1157
0
                dfK >= 0 && dfK <= INT_MAX && eBufType == GDT_Int32 &&
1158
0
                nPixelSpace == sizeof(int32_t) && eSrcType == GDT_Byte &&
1159
                // Limitation to avoid overflow of int32 if all source values are at the max of their data type
1160
0
                nSources <=
1161
0
                    (INT_MAX - dfK) / std::numeric_limits<uint8_t>::max())
1162
0
            {
1163
0
                bGeneralCase = false;
1164
0
                OptimizedSumPackedOutput<uint8_t, int32_t>(
1165
0
                    dfK, pData, nLineSpace, nXSize, nYSize, nSources,
1166
0
                    papoSources);
1167
0
            }
1168
1169
0
            if (bGeneralCase && dfK >= 0 && dfK <= INT_MAX &&
1170
0
                nSources <=
1171
0
                    (INT_MAX - dfK) / std::numeric_limits<uint16_t>::max())
1172
0
            {
1173
0
                bGeneralCase = !OptimizedSumThroughLargerType(
1174
0
                    eSrcType, eBufType, dfK, pData, nPixelSpace, nLineSpace,
1175
0
                    nXSize, nYSize, nSources, papoSources);
1176
0
            }
1177
0
        }
1178
1179
0
        if (bGeneralCase)
1180
0
        {
1181
0
            size_t ii = 0;
1182
0
            for (int iLine = 0; iLine < nYSize; ++iLine)
1183
0
            {
1184
0
                for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
1185
0
                {
1186
0
                    double dfSum = dfK;
1187
0
                    for (int iSrc = 0; iSrc < nSources; ++iSrc)
1188
0
                    {
1189
0
                        const double dfVal =
1190
0
                            GetSrcVal(papoSources[iSrc], eSrcType, ii);
1191
1192
0
                        if (bHasNoData && IsNoData(dfVal, dfNoData))
1193
0
                        {
1194
0
                            if (bPropagateNoData)
1195
0
                            {
1196
0
                                dfSum = dfNoData;
1197
0
                                break;
1198
0
                            }
1199
0
                        }
1200
0
                        else
1201
0
                        {
1202
0
                            dfSum += dfVal;
1203
0
                        }
1204
0
                    }
1205
1206
0
                    GDALCopyWords(&dfSum, GDT_Float64, 0,
1207
0
                                  static_cast<GByte *>(pData) +
1208
0
                                      static_cast<GSpacing>(nLineSpace) *
1209
0
                                          iLine +
1210
0
                                      iCol * nPixelSpace,
1211
0
                                  eBufType, nPixelSpace, 1);
1212
0
                }
1213
0
            }
1214
0
        }
1215
0
    }
1216
1217
    /* ---- Return success ---- */
1218
0
    return CE_None;
1219
0
} /* SumPixelFunc */
1220
1221
static const char pszDiffPixelFuncMetadata[] =
1222
    "<PixelFunctionArgumentsList>"
1223
    "   <Argument type='builtin' value='NoData' optional='true' />"
1224
    "</PixelFunctionArgumentsList>";
1225
1226
static CPLErr DiffPixelFunc(void **papoSources, int nSources, void *pData,
1227
                            int nXSize, int nYSize, GDALDataType eSrcType,
1228
                            GDALDataType eBufType, int nPixelSpace,
1229
                            int nLineSpace, CSLConstList papszArgs)
1230
0
{
1231
    /* ---- Init ---- */
1232
0
    if (nSources != 2)
1233
0
        return CE_Failure;
1234
1235
0
    double dfNoData{0};
1236
0
    const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
1237
0
    if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)
1238
0
        return CE_Failure;
1239
1240
0
    if (GDALDataTypeIsComplex(eSrcType))
1241
0
    {
1242
0
        const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;
1243
0
        const void *const pReal0 = papoSources[0];
1244
0
        const void *const pImag0 =
1245
0
            static_cast<GByte *>(papoSources[0]) + nOffset;
1246
0
        const void *const pReal1 = papoSources[1];
1247
0
        const void *const pImag1 =
1248
0
            static_cast<GByte *>(papoSources[1]) + nOffset;
1249
1250
        /* ---- Set pixels ---- */
1251
0
        size_t ii = 0;
1252
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
1253
0
        {
1254
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
1255
0
            {
1256
                // Source raster pixels may be obtained with GetSrcVal macro.
1257
0
                double adfPixVal[2] = {GetSrcVal(pReal0, eSrcType, ii) -
1258
0
                                           GetSrcVal(pReal1, eSrcType, ii),
1259
0
                                       GetSrcVal(pImag0, eSrcType, ii) -
1260
0
                                           GetSrcVal(pImag1, eSrcType, ii)};
1261
1262
0
                GDALCopyWords(adfPixVal, GDT_CFloat64, 0,
1263
0
                              static_cast<GByte *>(pData) +
1264
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
1265
0
                                  iCol * nPixelSpace,
1266
0
                              eBufType, nPixelSpace, 1);
1267
0
            }
1268
0
        }
1269
0
    }
1270
0
    else
1271
0
    {
1272
        /* ---- Set pixels ---- */
1273
0
        size_t ii = 0;
1274
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
1275
0
        {
1276
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
1277
0
            {
1278
0
                const double dfA = GetSrcVal(papoSources[0], eSrcType, ii);
1279
0
                const double dfB = GetSrcVal(papoSources[1], eSrcType, ii);
1280
1281
0
                const double dfPixVal =
1282
0
                    bHasNoData &&
1283
0
                            (IsNoData(dfA, dfNoData) || IsNoData(dfB, dfNoData))
1284
0
                        ? dfNoData
1285
0
                        : dfA - dfB;
1286
1287
0
                GDALCopyWords(&dfPixVal, GDT_Float64, 0,
1288
0
                              static_cast<GByte *>(pData) +
1289
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
1290
0
                                  iCol * nPixelSpace,
1291
0
                              eBufType, nPixelSpace, 1);
1292
0
            }
1293
0
        }
1294
0
    }
1295
1296
    /* ---- Return success ---- */
1297
0
    return CE_None;
1298
0
}  // DiffPixelFunc
1299
1300
static const char pszMulPixelFuncMetadata[] =
1301
    "<PixelFunctionArgumentsList>"
1302
    "   <Argument name='k' description='Optional constant factor' "
1303
    "type='double' default='1.0' />"
1304
    "   <Argument name='propagateNoData' description='Whether the output value "
1305
    "should be NoData as as soon as one source is NoData' type='boolean' "
1306
    "default='false' />"
1307
    "   <Argument type='builtin' value='NoData' optional='true' />"
1308
    "</PixelFunctionArgumentsList>";
1309
1310
static CPLErr MulPixelFunc(void **papoSources, int nSources, void *pData,
1311
                           int nXSize, int nYSize, GDALDataType eSrcType,
1312
                           GDALDataType eBufType, int nPixelSpace,
1313
                           int nLineSpace, CSLConstList papszArgs)
1314
0
{
1315
    /* ---- Init ---- */
1316
0
    if (nSources < 2 && CSLFetchNameValue(papszArgs, "k") == nullptr)
1317
0
    {
1318
0
        CPLError(CE_Failure, CPLE_AppDefined,
1319
0
                 "mul requires at least two sources or a specified constant k");
1320
0
        return CE_Failure;
1321
0
    }
1322
1323
0
    double dfK = 1.0;
1324
0
    if (FetchDoubleArg(papszArgs, "k", &dfK, &dfK) != CE_None)
1325
0
        return CE_Failure;
1326
1327
0
    double dfNoData{0};
1328
0
    const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
1329
0
    if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)
1330
0
        return CE_Failure;
1331
1332
0
    const bool bPropagateNoData = CPLTestBool(
1333
0
        CSLFetchNameValueDef(papszArgs, "propagateNoData", "false"));
1334
1335
    /* ---- Set pixels ---- */
1336
0
    if (GDALDataTypeIsComplex(eSrcType))
1337
0
    {
1338
0
        const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;
1339
1340
        /* ---- Set pixels ---- */
1341
0
        size_t ii = 0;
1342
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
1343
0
        {
1344
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
1345
0
            {
1346
0
                double adfPixVal[2] = {dfK, 0.0};
1347
1348
0
                for (int iSrc = 0; iSrc < nSources; ++iSrc)
1349
0
                {
1350
0
                    const void *const pReal = papoSources[iSrc];
1351
0
                    const void *const pImag =
1352
0
                        static_cast<const GByte *>(pReal) + nOffset;
1353
1354
0
                    const double dfOldR = adfPixVal[0];
1355
0
                    const double dfOldI = adfPixVal[1];
1356
1357
                    // Source raster pixels may be obtained with GetSrcVal
1358
                    // macro.
1359
0
                    const double dfNewR = GetSrcVal(pReal, eSrcType, ii);
1360
0
                    const double dfNewI = GetSrcVal(pImag, eSrcType, ii);
1361
1362
0
                    adfPixVal[0] = dfOldR * dfNewR - dfOldI * dfNewI;
1363
0
                    adfPixVal[1] = dfOldR * dfNewI + dfOldI * dfNewR;
1364
0
                }
1365
1366
0
                GDALCopyWords(adfPixVal, GDT_CFloat64, 0,
1367
0
                              static_cast<GByte *>(pData) +
1368
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
1369
0
                                  iCol * nPixelSpace,
1370
0
                              eBufType, nPixelSpace, 1);
1371
0
            }
1372
0
        }
1373
0
    }
1374
0
    else
1375
0
    {
1376
        /* ---- Set pixels ---- */
1377
0
        size_t ii = 0;
1378
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
1379
0
        {
1380
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
1381
0
            {
1382
0
                double dfPixVal = dfK;  // Not complex.
1383
1384
0
                for (int iSrc = 0; iSrc < nSources; ++iSrc)
1385
0
                {
1386
0
                    const double dfVal =
1387
0
                        GetSrcVal(papoSources[iSrc], eSrcType, ii);
1388
1389
0
                    if (bHasNoData && IsNoData(dfVal, dfNoData))
1390
0
                    {
1391
0
                        if (bPropagateNoData)
1392
0
                        {
1393
0
                            dfPixVal = dfNoData;
1394
0
                            break;
1395
0
                        }
1396
0
                    }
1397
0
                    else
1398
0
                    {
1399
0
                        dfPixVal *= dfVal;
1400
0
                    }
1401
0
                }
1402
1403
0
                GDALCopyWords(&dfPixVal, GDT_Float64, 0,
1404
0
                              static_cast<GByte *>(pData) +
1405
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
1406
0
                                  iCol * nPixelSpace,
1407
0
                              eBufType, nPixelSpace, 1);
1408
0
            }
1409
0
        }
1410
0
    }
1411
1412
    /* ---- Return success ---- */
1413
0
    return CE_None;
1414
0
}  // MulPixelFunc
1415
1416
static const char pszDivPixelFuncMetadata[] =
1417
    "<PixelFunctionArgumentsList>"
1418
    "   "
1419
    "<Argument type='builtin' value='NoData' optional='true' />"
1420
    "</PixelFunctionArgumentsList>";
1421
1422
static CPLErr DivPixelFunc(void **papoSources, int nSources, void *pData,
1423
                           int nXSize, int nYSize, GDALDataType eSrcType,
1424
                           GDALDataType eBufType, int nPixelSpace,
1425
                           int nLineSpace, CSLConstList papszArgs)
1426
0
{
1427
    /* ---- Init ---- */
1428
0
    if (nSources != 2)
1429
0
        return CE_Failure;
1430
1431
0
    double dfNoData{0};
1432
0
    const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
1433
0
    if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)
1434
0
        return CE_Failure;
1435
1436
    /* ---- Set pixels ---- */
1437
0
    if (GDALDataTypeIsComplex(eSrcType))
1438
0
    {
1439
0
        const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;
1440
0
        const void *const pReal0 = papoSources[0];
1441
0
        const void *const pImag0 =
1442
0
            static_cast<GByte *>(papoSources[0]) + nOffset;
1443
0
        const void *const pReal1 = papoSources[1];
1444
0
        const void *const pImag1 =
1445
0
            static_cast<GByte *>(papoSources[1]) + nOffset;
1446
1447
        /* ---- Set pixels ---- */
1448
0
        size_t ii = 0;
1449
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
1450
0
        {
1451
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
1452
0
            {
1453
                // Source raster pixels may be obtained with GetSrcVal macro.
1454
0
                const double dfReal0 = GetSrcVal(pReal0, eSrcType, ii);
1455
0
                const double dfReal1 = GetSrcVal(pReal1, eSrcType, ii);
1456
0
                const double dfImag0 = GetSrcVal(pImag0, eSrcType, ii);
1457
0
                const double dfImag1 = GetSrcVal(pImag1, eSrcType, ii);
1458
0
                const double dfAux = dfReal1 * dfReal1 + dfImag1 * dfImag1;
1459
1460
0
                const double adfPixVal[2] = {
1461
0
                    dfAux == 0
1462
0
                        ? std::numeric_limits<double>::infinity()
1463
0
                        : dfReal0 * dfReal1 / dfAux + dfImag0 * dfImag1 / dfAux,
1464
0
                    dfAux == 0 ? std::numeric_limits<double>::infinity()
1465
0
                               : dfReal1 / dfAux * dfImag0 -
1466
0
                                     dfReal0 * dfImag1 / dfAux};
1467
1468
0
                GDALCopyWords(adfPixVal, GDT_CFloat64, 0,
1469
0
                              static_cast<GByte *>(pData) +
1470
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
1471
0
                                  iCol * nPixelSpace,
1472
0
                              eBufType, nPixelSpace, 1);
1473
0
            }
1474
0
        }
1475
0
    }
1476
0
    else
1477
0
    {
1478
        /* ---- Set pixels ---- */
1479
0
        size_t ii = 0;
1480
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
1481
0
        {
1482
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
1483
0
            {
1484
0
                const double dfNum = GetSrcVal(papoSources[0], eSrcType, ii);
1485
0
                const double dfDenom = GetSrcVal(papoSources[1], eSrcType, ii);
1486
1487
0
                double dfPixVal = dfNoData;
1488
0
                if (!bHasNoData || (!IsNoData(dfNum, dfNoData) &&
1489
0
                                    !IsNoData(dfDenom, dfNoData)))
1490
0
                {
1491
                    // coverity[divide_by_zero]
1492
0
                    dfPixVal =
1493
0
                        dfDenom == 0
1494
0
                            ? std::numeric_limits<double>::infinity()
1495
0
                            : dfNum /
1496
#ifdef __COVERITY__
1497
                                  (dfDenom + std::numeric_limits<double>::min())
1498
#else
1499
0
                                  dfDenom
1500
0
#endif
1501
0
                        ;
1502
0
                }
1503
1504
0
                GDALCopyWords(&dfPixVal, GDT_Float64, 0,
1505
0
                              static_cast<GByte *>(pData) +
1506
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
1507
0
                                  iCol * nPixelSpace,
1508
0
                              eBufType, nPixelSpace, 1);
1509
0
            }
1510
0
        }
1511
0
    }
1512
1513
    /* ---- Return success ---- */
1514
0
    return CE_None;
1515
0
}  // DivPixelFunc
1516
1517
static CPLErr CMulPixelFunc(void **papoSources, int nSources, void *pData,
1518
                            int nXSize, int nYSize, GDALDataType eSrcType,
1519
                            GDALDataType eBufType, int nPixelSpace,
1520
                            int nLineSpace)
1521
0
{
1522
    /* ---- Init ---- */
1523
0
    if (nSources != 2)
1524
0
        return CE_Failure;
1525
1526
    /* ---- Set pixels ---- */
1527
0
    if (GDALDataTypeIsComplex(eSrcType))
1528
0
    {
1529
0
        const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;
1530
0
        const void *const pReal0 = papoSources[0];
1531
0
        const void *const pImag0 =
1532
0
            static_cast<GByte *>(papoSources[0]) + nOffset;
1533
0
        const void *const pReal1 = papoSources[1];
1534
0
        const void *const pImag1 =
1535
0
            static_cast<GByte *>(papoSources[1]) + nOffset;
1536
1537
0
        size_t ii = 0;
1538
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
1539
0
        {
1540
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
1541
0
            {
1542
                // Source raster pixels may be obtained with GetSrcVal macro.
1543
0
                const double dfReal0 = GetSrcVal(pReal0, eSrcType, ii);
1544
0
                const double dfReal1 = GetSrcVal(pReal1, eSrcType, ii);
1545
0
                const double dfImag0 = GetSrcVal(pImag0, eSrcType, ii);
1546
0
                const double dfImag1 = GetSrcVal(pImag1, eSrcType, ii);
1547
0
                const double adfPixVal[2] = {
1548
0
                    dfReal0 * dfReal1 + dfImag0 * dfImag1,
1549
0
                    dfReal1 * dfImag0 - dfReal0 * dfImag1};
1550
1551
0
                GDALCopyWords(adfPixVal, GDT_CFloat64, 0,
1552
0
                              static_cast<GByte *>(pData) +
1553
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
1554
0
                                  iCol * nPixelSpace,
1555
0
                              eBufType, nPixelSpace, 1);
1556
0
            }
1557
0
        }
1558
0
    }
1559
0
    else
1560
0
    {
1561
0
        size_t ii = 0;
1562
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
1563
0
        {
1564
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
1565
0
            {
1566
                // Source raster pixels may be obtained with GetSrcVal macro.
1567
                // Not complex.
1568
0
                const double adfPixVal[2] = {
1569
0
                    GetSrcVal(papoSources[0], eSrcType, ii) *
1570
0
                        GetSrcVal(papoSources[1], eSrcType, ii),
1571
0
                    0.0};
1572
1573
0
                GDALCopyWords(adfPixVal, GDT_CFloat64, 0,
1574
0
                              static_cast<GByte *>(pData) +
1575
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
1576
0
                                  iCol * nPixelSpace,
1577
0
                              eBufType, nPixelSpace, 1);
1578
0
            }
1579
0
        }
1580
0
    }
1581
1582
    /* ---- Return success ---- */
1583
0
    return CE_None;
1584
0
}  // CMulPixelFunc
1585
1586
static const char pszInvPixelFuncMetadata[] =
1587
    "<PixelFunctionArgumentsList>"
1588
    "   <Argument name='k' description='Optional constant factor' "
1589
    "type='double' default='1.0' />"
1590
    "   "
1591
    "<Argument type='builtin' value='NoData' optional='true' />"
1592
    "</PixelFunctionArgumentsList>";
1593
1594
static CPLErr InvPixelFunc(void **papoSources, int nSources, void *pData,
1595
                           int nXSize, int nYSize, GDALDataType eSrcType,
1596
                           GDALDataType eBufType, int nPixelSpace,
1597
                           int nLineSpace, CSLConstList papszArgs)
1598
0
{
1599
    /* ---- Init ---- */
1600
0
    if (nSources != 1)
1601
0
        return CE_Failure;
1602
1603
0
    double dfK = 1.0;
1604
0
    if (FetchDoubleArg(papszArgs, "k", &dfK, &dfK) != CE_None)
1605
0
        return CE_Failure;
1606
1607
0
    double dfNoData{0};
1608
0
    const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
1609
0
    if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)
1610
0
        return CE_Failure;
1611
1612
    /* ---- Set pixels ---- */
1613
0
    if (GDALDataTypeIsComplex(eSrcType))
1614
0
    {
1615
0
        const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;
1616
0
        const void *const pReal = papoSources[0];
1617
0
        const void *const pImag =
1618
0
            static_cast<GByte *>(papoSources[0]) + nOffset;
1619
1620
0
        size_t ii = 0;
1621
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
1622
0
        {
1623
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
1624
0
            {
1625
                // Source raster pixels may be obtained with GetSrcVal macro.
1626
0
                const double dfReal = GetSrcVal(pReal, eSrcType, ii);
1627
0
                const double dfImag = GetSrcVal(pImag, eSrcType, ii);
1628
0
                const double dfAux = dfReal * dfReal + dfImag * dfImag;
1629
0
                const double adfPixVal[2] = {
1630
0
                    dfAux == 0 ? std::numeric_limits<double>::infinity()
1631
0
                               : dfK * dfReal / dfAux,
1632
0
                    dfAux == 0 ? std::numeric_limits<double>::infinity()
1633
0
                               : -dfK * dfImag / dfAux};
1634
1635
0
                GDALCopyWords(adfPixVal, GDT_CFloat64, 0,
1636
0
                              static_cast<GByte *>(pData) +
1637
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
1638
0
                                  iCol * nPixelSpace,
1639
0
                              eBufType, nPixelSpace, 1);
1640
0
            }
1641
0
        }
1642
0
    }
1643
0
    else
1644
0
    {
1645
        /* ---- Set pixels ---- */
1646
0
        size_t ii = 0;
1647
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
1648
0
        {
1649
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
1650
0
            {
1651
                // Source raster pixels may be obtained with GetSrcVal macro.
1652
                // Not complex.
1653
0
                const double dfVal = GetSrcVal(papoSources[0], eSrcType, ii);
1654
0
                double dfPixVal = dfNoData;
1655
1656
0
                if (!bHasNoData || !IsNoData(dfVal, dfNoData))
1657
0
                {
1658
0
                    dfPixVal =
1659
0
                        dfVal == 0
1660
0
                            ? std::numeric_limits<double>::infinity()
1661
0
                            : dfK /
1662
#ifdef __COVERITY__
1663
                                  (dfVal + std::numeric_limits<double>::min())
1664
#else
1665
0
                                  dfVal
1666
0
#endif
1667
0
                        ;
1668
0
                }
1669
1670
0
                GDALCopyWords(&dfPixVal, GDT_Float64, 0,
1671
0
                              static_cast<GByte *>(pData) +
1672
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
1673
0
                                  iCol * nPixelSpace,
1674
0
                              eBufType, nPixelSpace, 1);
1675
0
            }
1676
0
        }
1677
0
    }
1678
1679
    /* ---- Return success ---- */
1680
0
    return CE_None;
1681
0
}  // InvPixelFunc
1682
1683
static CPLErr IntensityPixelFunc(void **papoSources, int nSources, void *pData,
1684
                                 int nXSize, int nYSize, GDALDataType eSrcType,
1685
                                 GDALDataType eBufType, int nPixelSpace,
1686
                                 int nLineSpace)
1687
0
{
1688
    /* ---- Init ---- */
1689
0
    if (nSources != 1)
1690
0
        return CE_Failure;
1691
1692
0
    if (GDALDataTypeIsComplex(eSrcType))
1693
0
    {
1694
0
        const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;
1695
0
        const void *const pReal = papoSources[0];
1696
0
        const void *const pImag =
1697
0
            static_cast<GByte *>(papoSources[0]) + nOffset;
1698
1699
        /* ---- Set pixels ---- */
1700
0
        size_t ii = 0;
1701
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
1702
0
        {
1703
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
1704
0
            {
1705
                // Source raster pixels may be obtained with GetSrcVal macro.
1706
0
                const double dfReal = GetSrcVal(pReal, eSrcType, ii);
1707
0
                const double dfImag = GetSrcVal(pImag, eSrcType, ii);
1708
1709
0
                const double dfPixVal = dfReal * dfReal + dfImag * dfImag;
1710
1711
0
                GDALCopyWords(&dfPixVal, GDT_Float64, 0,
1712
0
                              static_cast<GByte *>(pData) +
1713
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
1714
0
                                  iCol * nPixelSpace,
1715
0
                              eBufType, nPixelSpace, 1);
1716
0
            }
1717
0
        }
1718
0
    }
1719
0
    else
1720
0
    {
1721
        /* ---- Set pixels ---- */
1722
0
        size_t ii = 0;
1723
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
1724
0
        {
1725
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
1726
0
            {
1727
                // Source raster pixels may be obtained with GetSrcVal macro.
1728
0
                double dfPixVal = GetSrcVal(papoSources[0], eSrcType, ii);
1729
0
                dfPixVal *= dfPixVal;
1730
1731
0
                GDALCopyWords(&dfPixVal, GDT_Float64, 0,
1732
0
                              static_cast<GByte *>(pData) +
1733
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
1734
0
                                  iCol * nPixelSpace,
1735
0
                              eBufType, nPixelSpace, 1);
1736
0
            }
1737
0
        }
1738
0
    }
1739
1740
    /* ---- Return success ---- */
1741
0
    return CE_None;
1742
0
}  // IntensityPixelFunc
1743
1744
static const char pszSqrtPixelFuncMetadata[] =
1745
    "<PixelFunctionArgumentsList>"
1746
    "   <Argument type='builtin' value='NoData' optional='true'/>"
1747
    "</PixelFunctionArgumentsList>";
1748
1749
static CPLErr SqrtPixelFunc(void **papoSources, int nSources, void *pData,
1750
                            int nXSize, int nYSize, GDALDataType eSrcType,
1751
                            GDALDataType eBufType, int nPixelSpace,
1752
                            int nLineSpace, CSLConstList papszArgs)
1753
0
{
1754
    /* ---- Init ---- */
1755
0
    if (nSources != 1)
1756
0
        return CE_Failure;
1757
0
    if (GDALDataTypeIsComplex(eSrcType))
1758
0
        return CE_Failure;
1759
1760
0
    double dfNoData{0};
1761
0
    const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
1762
0
    if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)
1763
0
        return CE_Failure;
1764
1765
    /* ---- Set pixels ---- */
1766
0
    size_t ii = 0;
1767
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
1768
0
    {
1769
0
        for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
1770
0
        {
1771
            // Source raster pixels may be obtained with GetSrcVal macro.
1772
0
            double dfPixVal = GetSrcVal(papoSources[0], eSrcType, ii);
1773
1774
0
            if (bHasNoData && IsNoData(dfPixVal, dfNoData))
1775
0
            {
1776
0
                dfPixVal = dfNoData;
1777
0
            }
1778
0
            else
1779
0
            {
1780
0
                dfPixVal = std::sqrt(dfPixVal);
1781
0
            }
1782
1783
0
            GDALCopyWords(&dfPixVal, GDT_Float64, 0,
1784
0
                          static_cast<GByte *>(pData) +
1785
0
                              static_cast<GSpacing>(nLineSpace) * iLine +
1786
0
                              iCol * nPixelSpace,
1787
0
                          eBufType, nPixelSpace, 1);
1788
0
        }
1789
0
    }
1790
1791
    /* ---- Return success ---- */
1792
0
    return CE_None;
1793
0
}  // SqrtPixelFunc
1794
1795
static CPLErr Log10PixelFuncHelper(void **papoSources, int nSources,
1796
                                   void *pData, int nXSize, int nYSize,
1797
                                   GDALDataType eSrcType, GDALDataType eBufType,
1798
                                   int nPixelSpace, int nLineSpace,
1799
                                   CSLConstList papszArgs, double fact)
1800
0
{
1801
    /* ---- Init ---- */
1802
0
    if (nSources != 1)
1803
0
        return CE_Failure;
1804
1805
0
    double dfNoData{0};
1806
0
    const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
1807
0
    if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)
1808
0
        return CE_Failure;
1809
1810
0
    if (GDALDataTypeIsComplex(eSrcType))
1811
0
    {
1812
        // Complex input datatype.
1813
0
        const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;
1814
0
        const void *const pReal = papoSources[0];
1815
0
        const void *const pImag =
1816
0
            static_cast<GByte *>(papoSources[0]) + nOffset;
1817
1818
        /* We should compute fact * log10( sqrt( dfReal * dfReal + dfImag *
1819
         * dfImag ) ) */
1820
        /* Given that log10(sqrt(x)) = 0.5 * log10(x) */
1821
        /* we can remove the sqrt() by multiplying fact by 0.5 */
1822
0
        fact *= 0.5;
1823
1824
        /* ---- Set pixels ---- */
1825
0
        size_t ii = 0;
1826
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
1827
0
        {
1828
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
1829
0
            {
1830
                // Source raster pixels may be obtained with GetSrcVal macro.
1831
0
                const double dfReal = GetSrcVal(pReal, eSrcType, ii);
1832
0
                const double dfImag = GetSrcVal(pImag, eSrcType, ii);
1833
1834
0
                const double dfPixVal =
1835
0
                    fact * log10(dfReal * dfReal + dfImag * dfImag);
1836
1837
0
                GDALCopyWords(&dfPixVal, GDT_Float64, 0,
1838
0
                              static_cast<GByte *>(pData) +
1839
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
1840
0
                                  iCol * nPixelSpace,
1841
0
                              eBufType, nPixelSpace, 1);
1842
0
            }
1843
0
        }
1844
0
    }
1845
0
    else
1846
0
    {
1847
        /* ---- Set pixels ---- */
1848
0
        size_t ii = 0;
1849
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
1850
0
        {
1851
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
1852
0
            {
1853
                // Source raster pixels may be obtained with GetSrcVal macro.
1854
0
                const double dfSrcVal = GetSrcVal(papoSources[0], eSrcType, ii);
1855
0
                const double dfPixVal =
1856
0
                    bHasNoData && IsNoData(dfSrcVal, dfNoData)
1857
0
                        ? dfNoData
1858
0
                        : fact * std::log10(std::abs(dfSrcVal));
1859
1860
0
                GDALCopyWords(&dfPixVal, GDT_Float64, 0,
1861
0
                              static_cast<GByte *>(pData) +
1862
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
1863
0
                                  iCol * nPixelSpace,
1864
0
                              eBufType, nPixelSpace, 1);
1865
0
            }
1866
0
        }
1867
0
    }
1868
1869
    /* ---- Return success ---- */
1870
0
    return CE_None;
1871
0
}  // Log10PixelFuncHelper
1872
1873
static const char pszLog10PixelFuncMetadata[] =
1874
    "<PixelFunctionArgumentsList>"
1875
    "   <Argument type='builtin' value='NoData' optional='true'/>"
1876
    "</PixelFunctionArgumentsList>";
1877
1878
static CPLErr Log10PixelFunc(void **papoSources, int nSources, void *pData,
1879
                             int nXSize, int nYSize, GDALDataType eSrcType,
1880
                             GDALDataType eBufType, int nPixelSpace,
1881
                             int nLineSpace, CSLConstList papszArgs)
1882
0
{
1883
0
    return Log10PixelFuncHelper(papoSources, nSources, pData, nXSize, nYSize,
1884
0
                                eSrcType, eBufType, nPixelSpace, nLineSpace,
1885
0
                                papszArgs, 1.0);
1886
0
}  // Log10PixelFunc
1887
1888
static const char pszDBPixelFuncMetadata[] =
1889
    "<PixelFunctionArgumentsList>"
1890
    "   <Argument name='fact' description='Factor' type='double' "
1891
    "default='20.0' />"
1892
    "   <Argument type='builtin' value='NoData' optional='true' />"
1893
    "</PixelFunctionArgumentsList>";
1894
1895
static CPLErr DBPixelFunc(void **papoSources, int nSources, void *pData,
1896
                          int nXSize, int nYSize, GDALDataType eSrcType,
1897
                          GDALDataType eBufType, int nPixelSpace,
1898
                          int nLineSpace, CSLConstList papszArgs)
1899
0
{
1900
0
    double dfFact = 20.;
1901
0
    if (FetchDoubleArg(papszArgs, "fact", &dfFact, &dfFact) != CE_None)
1902
0
        return CE_Failure;
1903
1904
0
    return Log10PixelFuncHelper(papoSources, nSources, pData, nXSize, nYSize,
1905
0
                                eSrcType, eBufType, nPixelSpace, nLineSpace,
1906
0
                                papszArgs, dfFact);
1907
0
}  // DBPixelFunc
1908
1909
static CPLErr ExpPixelFuncHelper(void **papoSources, int nSources, void *pData,
1910
                                 int nXSize, int nYSize, GDALDataType eSrcType,
1911
                                 GDALDataType eBufType, int nPixelSpace,
1912
                                 int nLineSpace, CSLConstList papszArgs,
1913
                                 double base, double fact)
1914
0
{
1915
    /* ---- Init ---- */
1916
0
    if (nSources != 1)
1917
0
        return CE_Failure;
1918
0
    if (GDALDataTypeIsComplex(eSrcType))
1919
0
        return CE_Failure;
1920
1921
0
    double dfNoData{0};
1922
0
    const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
1923
0
    if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)
1924
0
        return CE_Failure;
1925
1926
    /* ---- Set pixels ---- */
1927
0
    size_t ii = 0;
1928
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
1929
0
    {
1930
0
        for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
1931
0
        {
1932
            // Source raster pixels may be obtained with GetSrcVal macro.
1933
0
            const double dfVal = GetSrcVal(papoSources[0], eSrcType, ii);
1934
0
            const double dfPixVal = bHasNoData && IsNoData(dfVal, dfNoData)
1935
0
                                        ? dfNoData
1936
0
                                        : pow(base, dfVal * fact);
1937
1938
0
            GDALCopyWords(&dfPixVal, GDT_Float64, 0,
1939
0
                          static_cast<GByte *>(pData) +
1940
0
                              static_cast<GSpacing>(nLineSpace) * iLine +
1941
0
                              iCol * nPixelSpace,
1942
0
                          eBufType, nPixelSpace, 1);
1943
0
        }
1944
0
    }
1945
1946
    /* ---- Return success ---- */
1947
0
    return CE_None;
1948
0
}  // ExpPixelFuncHelper
1949
1950
static const char pszExpPixelFuncMetadata[] =
1951
    "<PixelFunctionArgumentsList>"
1952
    "   <Argument name='base' description='Base' type='double' "
1953
    "default='2.7182818284590452353602874713526624' />"
1954
    "   <Argument name='fact' description='Factor' type='double' default='1' />"
1955
    "   <Argument type='builtin' value='NoData' optional='true' />"
1956
    "</PixelFunctionArgumentsList>";
1957
1958
static CPLErr ExpPixelFunc(void **papoSources, int nSources, void *pData,
1959
                           int nXSize, int nYSize, GDALDataType eSrcType,
1960
                           GDALDataType eBufType, int nPixelSpace,
1961
                           int nLineSpace, CSLConstList papszArgs)
1962
0
{
1963
0
    double dfBase = 2.7182818284590452353602874713526624;
1964
0
    double dfFact = 1.;
1965
1966
0
    if (FetchDoubleArg(papszArgs, "base", &dfBase, &dfBase) != CE_None)
1967
0
        return CE_Failure;
1968
1969
0
    if (FetchDoubleArg(papszArgs, "fact", &dfFact, &dfFact) != CE_None)
1970
0
        return CE_Failure;
1971
1972
0
    return ExpPixelFuncHelper(papoSources, nSources, pData, nXSize, nYSize,
1973
0
                              eSrcType, eBufType, nPixelSpace, nLineSpace,
1974
0
                              papszArgs, dfBase, dfFact);
1975
0
}  // ExpPixelFunc
1976
1977
static CPLErr dB2AmpPixelFunc(void **papoSources, int nSources, void *pData,
1978
                              int nXSize, int nYSize, GDALDataType eSrcType,
1979
                              GDALDataType eBufType, int nPixelSpace,
1980
                              int nLineSpace)
1981
0
{
1982
0
    return ExpPixelFuncHelper(papoSources, nSources, pData, nXSize, nYSize,
1983
0
                              eSrcType, eBufType, nPixelSpace, nLineSpace,
1984
0
                              nullptr, 10.0, 1. / 20);
1985
0
}  // dB2AmpPixelFunc
1986
1987
static CPLErr dB2PowPixelFunc(void **papoSources, int nSources, void *pData,
1988
                              int nXSize, int nYSize, GDALDataType eSrcType,
1989
                              GDALDataType eBufType, int nPixelSpace,
1990
                              int nLineSpace)
1991
0
{
1992
0
    return ExpPixelFuncHelper(papoSources, nSources, pData, nXSize, nYSize,
1993
0
                              eSrcType, eBufType, nPixelSpace, nLineSpace,
1994
0
                              nullptr, 10.0, 1. / 10);
1995
0
}  // dB2PowPixelFunc
1996
1997
static const char pszPowPixelFuncMetadata[] =
1998
    "<PixelFunctionArgumentsList>"
1999
    "   <Argument name='power' description='Exponent' type='double' "
2000
    "mandatory='1' />"
2001
    "   <Argument type='builtin' value='NoData' optional='true' />"
2002
    "</PixelFunctionArgumentsList>";
2003
2004
static CPLErr PowPixelFunc(void **papoSources, int nSources, void *pData,
2005
                           int nXSize, int nYSize, GDALDataType eSrcType,
2006
                           GDALDataType eBufType, int nPixelSpace,
2007
                           int nLineSpace, CSLConstList papszArgs)
2008
0
{
2009
    /* ---- Init ---- */
2010
0
    if (nSources != 1)
2011
0
        return CE_Failure;
2012
0
    if (GDALDataTypeIsComplex(eSrcType))
2013
0
        return CE_Failure;
2014
2015
0
    double power;
2016
0
    if (FetchDoubleArg(papszArgs, "power", &power) != CE_None)
2017
0
        return CE_Failure;
2018
2019
0
    double dfNoData{0};
2020
0
    const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
2021
0
    if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)
2022
0
        return CE_Failure;
2023
2024
    /* ---- Set pixels ---- */
2025
0
    size_t ii = 0;
2026
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
2027
0
    {
2028
0
        for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
2029
0
        {
2030
0
            const double dfVal = GetSrcVal(papoSources[0], eSrcType, ii);
2031
2032
0
            const double dfPixVal = bHasNoData && IsNoData(dfVal, dfNoData)
2033
0
                                        ? dfNoData
2034
0
                                        : std::pow(dfVal, power);
2035
2036
0
            GDALCopyWords(&dfPixVal, GDT_Float64, 0,
2037
0
                          static_cast<GByte *>(pData) +
2038
0
                              static_cast<GSpacing>(nLineSpace) * iLine +
2039
0
                              iCol * nPixelSpace,
2040
0
                          eBufType, nPixelSpace, 1);
2041
0
        }
2042
0
    }
2043
2044
    /* ---- Return success ---- */
2045
0
    return CE_None;
2046
0
}
2047
2048
// Given nt intervals spaced by dt and beginning at t0, return the index of
2049
// the lower bound of the interval that should be used to
2050
// interpolate/extrapolate a value for t.
2051
static std::size_t intervalLeft(double t0, double dt, std::size_t nt, double t)
2052
0
{
2053
0
    if (t < t0)
2054
0
    {
2055
0
        return 0;
2056
0
    }
2057
2058
0
    std::size_t n = static_cast<std::size_t>((t - t0) / dt);
2059
2060
0
    if (n >= nt - 1)
2061
0
    {
2062
0
        return nt - 2;
2063
0
    }
2064
2065
0
    return n;
2066
0
}
2067
2068
static double InterpolateLinear(double dfX0, double dfX1, double dfY0,
2069
                                double dfY1, double dfX)
2070
0
{
2071
0
    return dfY0 + (dfX - dfX0) * (dfY1 - dfY0) / (dfX1 - dfX0);
2072
0
}
2073
2074
static double InterpolateExponential(double dfX0, double dfX1, double dfY0,
2075
                                     double dfY1, double dfX)
2076
0
{
2077
0
    const double r = std::log(dfY1 / dfY0) / (dfX1 - dfX0);
2078
0
    return dfY0 * std::exp(r * (dfX - dfX0));
2079
0
}
2080
2081
static const char pszInterpolatePixelFuncMetadata[] =
2082
    "<PixelFunctionArgumentsList>"
2083
    "   <Argument name='t0' description='t0' type='double' mandatory='1' />"
2084
    "   <Argument name='dt' description='dt' type='double' mandatory='1' />"
2085
    "   <Argument name='t' description='t' type='double' mandatory='1' />"
2086
    "   <Argument type='builtin' value='NoData' optional='true' />"
2087
    "</PixelFunctionArgumentsList>";
2088
2089
template <decltype(InterpolateLinear) InterpolationFunction>
2090
CPLErr InterpolatePixelFunc(void **papoSources, int nSources, void *pData,
2091
                            int nXSize, int nYSize, GDALDataType eSrcType,
2092
                            GDALDataType eBufType, int nPixelSpace,
2093
                            int nLineSpace, CSLConstList papszArgs)
2094
0
{
2095
    /* ---- Init ---- */
2096
0
    if (GDALDataTypeIsComplex(eSrcType))
2097
0
        return CE_Failure;
2098
2099
0
    double dfT0;
2100
0
    if (FetchDoubleArg(papszArgs, "t0", &dfT0) == CE_Failure)
2101
0
        return CE_Failure;
2102
2103
0
    double dfT;
2104
0
    if (FetchDoubleArg(papszArgs, "t", &dfT) == CE_Failure)
2105
0
        return CE_Failure;
2106
2107
0
    double dfDt;
2108
0
    if (FetchDoubleArg(papszArgs, "dt", &dfDt) == CE_Failure)
2109
0
        return CE_Failure;
2110
2111
0
    double dfNoData{0};
2112
0
    const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
2113
0
    if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)
2114
0
        return CE_Failure;
2115
2116
0
    if (nSources < 2)
2117
0
    {
2118
0
        CPLError(CE_Failure, CPLE_AppDefined,
2119
0
                 "At least two sources required for interpolation.");
2120
0
        return CE_Failure;
2121
0
    }
2122
2123
0
    if (dfT == 0 || !std::isfinite(dfT))
2124
0
    {
2125
0
        CPLError(CE_Failure, CPLE_AppDefined, "dt must be finite and non-zero");
2126
0
        return CE_Failure;
2127
0
    }
2128
2129
0
    const auto i0 = intervalLeft(dfT0, dfDt, nSources, dfT);
2130
0
    const auto i1 = i0 + 1;
2131
0
    const double dfX0 = dfT0 + static_cast<double>(i0) * dfDt;
2132
0
    const double dfX1 = dfT0 + static_cast<double>(i0 + 1) * dfDt;
2133
2134
    /* ---- Set pixels ---- */
2135
0
    size_t ii = 0;
2136
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
2137
0
    {
2138
0
        for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
2139
0
        {
2140
0
            const double dfY0 = GetSrcVal(papoSources[i0], eSrcType, ii);
2141
0
            const double dfY1 = GetSrcVal(papoSources[i1], eSrcType, ii);
2142
2143
0
            double dfPixVal = dfNoData;
2144
0
            if (dfT == dfX0)
2145
0
                dfPixVal = dfY0;
2146
0
            else if (dfT == dfX1)
2147
0
                dfPixVal = dfY1;
2148
0
            else if (!bHasNoData ||
2149
0
                     (!IsNoData(dfY0, dfNoData) && !IsNoData(dfY1, dfNoData)))
2150
0
                dfPixVal = InterpolationFunction(dfX0, dfX1, dfY0, dfY1, dfT);
2151
2152
0
            GDALCopyWords(&dfPixVal, GDT_Float64, 0,
2153
0
                          static_cast<GByte *>(pData) +
2154
0
                              static_cast<GSpacing>(nLineSpace) * iLine +
2155
0
                              iCol * nPixelSpace,
2156
0
                          eBufType, nPixelSpace, 1);
2157
0
        }
2158
0
    }
2159
2160
    /* ---- Return success ---- */
2161
0
    return CE_None;
2162
0
}
Unexecuted instantiation: pixelfunctions.cpp:CPLErr InterpolatePixelFunc<&(InterpolateLinear(double, double, double, double, double))>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)
Unexecuted instantiation: pixelfunctions.cpp:CPLErr InterpolatePixelFunc<&(InterpolateExponential(double, double, double, double, double))>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)
2163
2164
static const char pszReplaceNoDataPixelFuncMetadata[] =
2165
    "<PixelFunctionArgumentsList>"
2166
    "   <Argument type='builtin' value='NoData' />"
2167
    "   <Argument name='to' type='double' description='New NoData value to be "
2168
    "replaced' default='nan' />"
2169
    "</PixelFunctionArgumentsList>";
2170
2171
static CPLErr ReplaceNoDataPixelFunc(void **papoSources, int nSources,
2172
                                     void *pData, int nXSize, int nYSize,
2173
                                     GDALDataType eSrcType,
2174
                                     GDALDataType eBufType, int nPixelSpace,
2175
                                     int nLineSpace, CSLConstList papszArgs)
2176
0
{
2177
    /* ---- Init ---- */
2178
0
    if (nSources != 1)
2179
0
        return CE_Failure;
2180
0
    if (GDALDataTypeIsComplex(eSrcType))
2181
0
    {
2182
0
        CPLError(CE_Failure, CPLE_AppDefined,
2183
0
                 "replace_nodata cannot convert complex data types");
2184
0
        return CE_Failure;
2185
0
    }
2186
2187
0
    double dfOldNoData, dfNewNoData = NAN;
2188
0
    if (FetchDoubleArg(papszArgs, "NoData", &dfOldNoData) != CE_None)
2189
0
        return CE_Failure;
2190
0
    if (FetchDoubleArg(papszArgs, "to", &dfNewNoData, &dfNewNoData) != CE_None)
2191
0
        return CE_Failure;
2192
2193
0
    if (!GDALDataTypeIsFloating(eBufType) && std::isnan(dfNewNoData))
2194
0
    {
2195
0
        CPLError(CE_Failure, CPLE_AppDefined,
2196
0
                 "Using nan requires a floating point type output buffer");
2197
0
        return CE_Failure;
2198
0
    }
2199
2200
    /* ---- Set pixels ---- */
2201
0
    size_t ii = 0;
2202
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
2203
0
    {
2204
0
        for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
2205
0
        {
2206
0
            double dfPixVal = GetSrcVal(papoSources[0], eSrcType, ii);
2207
0
            if (dfPixVal == dfOldNoData || std::isnan(dfPixVal))
2208
0
                dfPixVal = dfNewNoData;
2209
2210
0
            GDALCopyWords(&dfPixVal, GDT_Float64, 0,
2211
0
                          static_cast<GByte *>(pData) +
2212
0
                              static_cast<GSpacing>(nLineSpace) * iLine +
2213
0
                              iCol * nPixelSpace,
2214
0
                          eBufType, nPixelSpace, 1);
2215
0
        }
2216
0
    }
2217
2218
    /* ---- Return success ---- */
2219
0
    return CE_None;
2220
0
}
2221
2222
static const char pszScalePixelFuncMetadata[] =
2223
    "<PixelFunctionArgumentsList>"
2224
    "   <Argument type='builtin' value='offset' />"
2225
    "   <Argument type='builtin' value='scale' />"
2226
    "   <Argument type='builtin' value='NoData' optional='true' />"
2227
    "</PixelFunctionArgumentsList>";
2228
2229
static CPLErr ScalePixelFunc(void **papoSources, int nSources, void *pData,
2230
                             int nXSize, int nYSize, GDALDataType eSrcType,
2231
                             GDALDataType eBufType, int nPixelSpace,
2232
                             int nLineSpace, CSLConstList papszArgs)
2233
0
{
2234
    /* ---- Init ---- */
2235
0
    if (nSources != 1)
2236
0
        return CE_Failure;
2237
0
    if (GDALDataTypeIsComplex(eSrcType))
2238
0
    {
2239
0
        CPLError(CE_Failure, CPLE_AppDefined,
2240
0
                 "scale cannot by applied to complex data types");
2241
0
        return CE_Failure;
2242
0
    }
2243
2244
0
    double dfNoData{0};
2245
0
    const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
2246
0
    if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)
2247
0
        return CE_Failure;
2248
2249
0
    double dfScale, dfOffset;
2250
0
    if (FetchDoubleArg(papszArgs, "scale", &dfScale) != CE_None)
2251
0
        return CE_Failure;
2252
0
    if (FetchDoubleArg(papszArgs, "offset", &dfOffset) != CE_None)
2253
0
        return CE_Failure;
2254
2255
    /* ---- Set pixels ---- */
2256
0
    size_t ii = 0;
2257
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
2258
0
    {
2259
0
        for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
2260
0
        {
2261
0
            const double dfVal = GetSrcVal(papoSources[0], eSrcType, ii);
2262
2263
0
            const double dfPixVal = bHasNoData && IsNoData(dfVal, dfNoData)
2264
0
                                        ? dfNoData
2265
0
                                        : dfVal * dfScale + dfOffset;
2266
2267
0
            GDALCopyWords(&dfPixVal, GDT_Float64, 0,
2268
0
                          static_cast<GByte *>(pData) +
2269
0
                              static_cast<GSpacing>(nLineSpace) * iLine +
2270
0
                              iCol * nPixelSpace,
2271
0
                          eBufType, nPixelSpace, 1);
2272
0
        }
2273
0
    }
2274
2275
    /* ---- Return success ---- */
2276
0
    return CE_None;
2277
0
}
2278
2279
static const char pszNormDiffPixelFuncMetadata[] =
2280
    "<PixelFunctionArgumentsList>"
2281
    "   <Argument type='builtin' value='NoData' optional='true' />"
2282
    "</PixelFunctionArgumentsList>";
2283
2284
static CPLErr NormDiffPixelFunc(void **papoSources, int nSources, void *pData,
2285
                                int nXSize, int nYSize, GDALDataType eSrcType,
2286
                                GDALDataType eBufType, int nPixelSpace,
2287
                                int nLineSpace, CSLConstList papszArgs)
2288
0
{
2289
    /* ---- Init ---- */
2290
0
    if (nSources != 2)
2291
0
        return CE_Failure;
2292
2293
0
    if (GDALDataTypeIsComplex(eSrcType))
2294
0
    {
2295
0
        CPLError(CE_Failure, CPLE_AppDefined,
2296
0
                 "norm_diff cannot by applied to complex data types");
2297
0
        return CE_Failure;
2298
0
    }
2299
2300
0
    double dfNoData{0};
2301
0
    const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
2302
0
    if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)
2303
0
        return CE_Failure;
2304
2305
    /* ---- Set pixels ---- */
2306
0
    size_t ii = 0;
2307
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
2308
0
    {
2309
0
        for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
2310
0
        {
2311
0
            const double dfLeftVal = GetSrcVal(papoSources[0], eSrcType, ii);
2312
0
            const double dfRightVal = GetSrcVal(papoSources[1], eSrcType, ii);
2313
2314
0
            double dfPixVal = dfNoData;
2315
2316
0
            if (!bHasNoData || (!IsNoData(dfLeftVal, dfNoData) &&
2317
0
                                !IsNoData(dfRightVal, dfNoData)))
2318
0
            {
2319
0
                const double dfDenom = (dfLeftVal + dfRightVal);
2320
                // coverity[divide_by_zero]
2321
0
                dfPixVal =
2322
0
                    dfDenom == 0
2323
0
                        ? std::numeric_limits<double>::infinity()
2324
0
                        : (dfLeftVal - dfRightVal) /
2325
#ifdef __COVERITY__
2326
                              (dfDenom + std::numeric_limits<double>::min())
2327
#else
2328
0
                              dfDenom
2329
0
#endif
2330
0
                    ;
2331
0
            }
2332
2333
0
            GDALCopyWords(&dfPixVal, GDT_Float64, 0,
2334
0
                          static_cast<GByte *>(pData) +
2335
0
                              static_cast<GSpacing>(nLineSpace) * iLine +
2336
0
                              iCol * nPixelSpace,
2337
0
                          eBufType, nPixelSpace, 1);
2338
0
        }
2339
0
    }
2340
2341
    /* ---- Return success ---- */
2342
0
    return CE_None;
2343
0
}  // NormDiffPixelFunc
2344
2345
/************************************************************************/
2346
/*                   pszMinMaxFuncMetadataNodata                        */
2347
/************************************************************************/
2348
2349
static const char pszArgMinMaxFuncMetadataNodata[] =
2350
    "<PixelFunctionArgumentsList>"
2351
    "   <Argument type='builtin' value='NoData' optional='true' />"
2352
    "   <Argument name='propagateNoData' description='Whether the output value "
2353
    "should be NoData as as soon as one source is NoData' type='boolean' "
2354
    "default='false' />"
2355
    "</PixelFunctionArgumentsList>";
2356
2357
static const char pszMinMaxFuncMetadataNodata[] =
2358
    "<PixelFunctionArgumentsList>"
2359
    "   <Argument name='k' description='Optional constant term' type='double' "
2360
    "default='nan' />"
2361
    "   <Argument type='builtin' value='NoData' optional='true' />"
2362
    "   <Argument name='propagateNoData' description='Whether the output value "
2363
    "should be NoData as as soon as one source is NoData' type='boolean' "
2364
    "default='false' />"
2365
    "</PixelFunctionArgumentsList>";
2366
2367
namespace
2368
{
2369
struct ReturnIndex;
2370
struct ReturnValue;
2371
}  // namespace
2372
2373
template <class Comparator, class ReturnType = ReturnValue>
2374
static CPLErr MinOrMaxPixelFunc(double dfK, void **papoSources, int nSources,
2375
                                void *pData, int nXSize, int nYSize,
2376
                                GDALDataType eSrcType, GDALDataType eBufType,
2377
                                int nPixelSpace, int nLineSpace,
2378
                                CSLConstList papszArgs)
2379
0
{
2380
    /* ---- Init ---- */
2381
0
    if (GDALDataTypeIsComplex(eSrcType))
2382
0
    {
2383
0
        CPLError(CE_Failure, CPLE_AppDefined,
2384
0
                 "Complex data type not supported for min/max().");
2385
0
        return CE_Failure;
2386
0
    }
2387
2388
0
    double dfNoData = std::numeric_limits<double>::quiet_NaN();
2389
0
    if (FetchDoubleArg(papszArgs, "NoData", &dfNoData, &dfNoData) != CE_None)
2390
0
        return CE_Failure;
2391
0
    const bool bPropagateNoData = CPLTestBool(
2392
0
        CSLFetchNameValueDef(papszArgs, "propagateNoData", "false"));
2393
2394
    /* ---- Set pixels ---- */
2395
0
    size_t ii = 0;
2396
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
2397
0
    {
2398
0
        for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
2399
0
        {
2400
0
            double dfRes = std::numeric_limits<double>::quiet_NaN();
2401
0
            double dfResSrc = std::numeric_limits<double>::quiet_NaN();
2402
2403
0
            for (int iSrc = 0; iSrc < nSources; ++iSrc)
2404
0
            {
2405
0
                const double dfVal = GetSrcVal(papoSources[iSrc], eSrcType, ii);
2406
2407
0
                if (std::isnan(dfVal) || dfVal == dfNoData)
2408
0
                {
2409
0
                    if (bPropagateNoData)
2410
0
                    {
2411
0
                        dfRes = dfNoData;
2412
                        if constexpr (std::is_same_v<ReturnType, ReturnIndex>)
2413
0
                        {
2414
0
                            dfResSrc = std::numeric_limits<double>::quiet_NaN();
2415
0
                        }
2416
0
                        break;
2417
0
                    }
2418
0
                }
2419
0
                else if (Comparator::compare(dfVal, dfRes))
2420
0
                {
2421
0
                    dfRes = dfVal;
2422
                    if constexpr (std::is_same_v<ReturnType, ReturnIndex>)
2423
0
                    {
2424
0
                        dfResSrc = iSrc;
2425
0
                    }
2426
0
                }
2427
0
            }
2428
2429
            if constexpr (std::is_same_v<ReturnType, ReturnIndex>)
2430
0
            {
2431
0
                static_cast<void>(dfK);  // Placate gcc 9.4
2432
0
                dfRes = std::isnan(dfResSrc) ? dfNoData : dfResSrc + 1;
2433
            }
2434
            else
2435
0
            {
2436
0
                if (std::isnan(dfRes))
2437
0
                {
2438
0
                    dfRes = dfNoData;
2439
0
                }
2440
2441
0
                if (IsNoData(dfRes, dfNoData))
2442
0
                {
2443
0
                    if (!bPropagateNoData && !std::isnan(dfK))
2444
0
                    {
2445
0
                        dfRes = dfK;
2446
0
                    }
2447
0
                }
2448
0
                else if (!std::isnan(dfK) && Comparator::compare(dfK, dfRes))
2449
0
                {
2450
0
                    dfRes = dfK;
2451
0
                }
2452
0
            }
2453
2454
0
            GDALCopyWords(&dfRes, GDT_Float64, 0,
2455
0
                          static_cast<GByte *>(pData) +
2456
0
                              static_cast<GSpacing>(nLineSpace) * iLine +
2457
0
                              iCol * nPixelSpace,
2458
0
                          eBufType, nPixelSpace, 1);
2459
0
        }
2460
0
    }
2461
2462
    /* ---- Return success ---- */
2463
0
    return CE_None;
2464
0
} /* MinOrMaxPixelFunc */
Unexecuted instantiation: pixelfunctions.cpp:CPLErr MinOrMaxPixelFunc<MinPixelFunc<(anonymous namespace)::ReturnValue>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)::Comparator, (anonymous namespace)::ReturnValue>(double, void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)
Unexecuted instantiation: pixelfunctions.cpp:CPLErr MinOrMaxPixelFunc<MinPixelFunc<(anonymous namespace)::ReturnIndex>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)::Comparator, (anonymous namespace)::ReturnIndex>(double, void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)
Unexecuted instantiation: pixelfunctions.cpp:CPLErr MinOrMaxPixelFunc<MaxPixelFunc<(anonymous namespace)::ReturnValue>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)::Comparator, (anonymous namespace)::ReturnValue>(double, void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)
Unexecuted instantiation: pixelfunctions.cpp:CPLErr MinOrMaxPixelFunc<MaxPixelFunc<(anonymous namespace)::ReturnIndex>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)::Comparator, (anonymous namespace)::ReturnIndex>(double, void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)
2465
2466
#ifdef USE_SSE2
2467
2468
template <class T, class SSEWrapper>
2469
static void OptimizedMinOrMaxSSE2(const void *const *papoSources, int nSources,
2470
                                  void *pData, int nXSize, int nYSize,
2471
                                  int nLineSpace)
2472
0
{
2473
0
    assert(nSources >= 1);
2474
0
    constexpr int VALUES_PER_REG =
2475
0
        static_cast<int>(sizeof(typename SSEWrapper::Vec) / sizeof(T));
2476
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
2477
0
    {
2478
0
        T *CPL_RESTRICT pDest =
2479
0
            reinterpret_cast<T *>(static_cast<GByte *>(pData) +
2480
0
                                  static_cast<GSpacing>(nLineSpace) * iLine);
2481
0
        const size_t iOffsetLine = static_cast<size_t>(iLine) * nXSize;
2482
0
        int iCol = 0;
2483
0
        for (; iCol < nXSize - (2 * VALUES_PER_REG - 1);
2484
0
             iCol += 2 * VALUES_PER_REG)
2485
0
        {
2486
0
            auto reg0 = SSEWrapper::LoadU(
2487
0
                static_cast<const T * CPL_RESTRICT>(papoSources[0]) +
2488
0
                iOffsetLine + iCol);
2489
0
            auto reg1 = SSEWrapper::LoadU(
2490
0
                static_cast<const T * CPL_RESTRICT>(papoSources[0]) +
2491
0
                iOffsetLine + iCol + VALUES_PER_REG);
2492
0
            for (int iSrc = 1; iSrc < nSources; ++iSrc)
2493
0
            {
2494
0
                reg0 = SSEWrapper::MinOrMax(
2495
0
                    reg0, SSEWrapper::LoadU(static_cast<const T * CPL_RESTRICT>(
2496
0
                                                papoSources[iSrc]) +
2497
0
                                            iOffsetLine + iCol));
2498
0
                reg1 = SSEWrapper::MinOrMax(
2499
0
                    reg1,
2500
0
                    SSEWrapper::LoadU(
2501
0
                        static_cast<const T * CPL_RESTRICT>(papoSources[iSrc]) +
2502
0
                        iOffsetLine + iCol + VALUES_PER_REG));
2503
0
            }
2504
0
            SSEWrapper::StoreU(pDest + iCol, reg0);
2505
0
            SSEWrapper::StoreU(pDest + iCol + VALUES_PER_REG, reg1);
2506
0
        }
2507
0
        for (; iCol < nXSize; ++iCol)
2508
0
        {
2509
0
            T v = static_cast<const T * CPL_RESTRICT>(
2510
0
                papoSources[0])[iOffsetLine + iCol];
2511
0
            for (int iSrc = 1; iSrc < nSources; ++iSrc)
2512
0
            {
2513
0
                v = SSEWrapper::MinOrMax(
2514
0
                    v, static_cast<const T * CPL_RESTRICT>(
2515
0
                           papoSources[iSrc])[iOffsetLine + iCol]);
2516
0
            }
2517
0
            pDest[iCol] = v;
2518
0
        }
2519
0
    }
2520
0
}
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedMinOrMaxSSE2<unsigned char, (anonymous namespace)::SSEWrapperMinByte>(void const* const*, int, void*, int, int, int)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedMinOrMaxSSE2<unsigned short, (anonymous namespace)::SSEWrapperMinUInt16>(void const* const*, int, void*, int, int, int)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedMinOrMaxSSE2<short, (anonymous namespace)::SSEWrapperMinInt16>(void const* const*, int, void*, int, int, int)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedMinOrMaxSSE2<float, (anonymous namespace)::SSEWrapperMinFloat>(void const* const*, int, void*, int, int, int)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedMinOrMaxSSE2<double, (anonymous namespace)::SSEWrapperMinDouble>(void const* const*, int, void*, int, int, int)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedMinOrMaxSSE2<unsigned char, (anonymous namespace)::SSEWrapperMaxByte>(void const* const*, int, void*, int, int, int)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedMinOrMaxSSE2<unsigned short, (anonymous namespace)::SSEWrapperMaxUInt16>(void const* const*, int, void*, int, int, int)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedMinOrMaxSSE2<short, (anonymous namespace)::SSEWrapperMaxInt16>(void const* const*, int, void*, int, int, int)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedMinOrMaxSSE2<float, (anonymous namespace)::SSEWrapperMaxFloat>(void const* const*, int, void*, int, int, int)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedMinOrMaxSSE2<double, (anonymous namespace)::SSEWrapperMaxDouble>(void const* const*, int, void*, int, int, int)
2521
2522
// clang-format off
2523
namespace
2524
{
2525
struct SSEWrapperMinByte
2526
{
2527
    using T = uint8_t;
2528
    typedef __m128i Vec;
2529
2530
0
    static inline Vec LoadU(const T *x) { return _mm_loadu_si128(reinterpret_cast<const Vec*>(x)); }
2531
0
    static inline void StoreU(T *x, Vec y) { _mm_storeu_si128(reinterpret_cast<Vec*>(x), y); }
2532
0
    static inline Vec MinOrMax(Vec x, Vec y) { return _mm_min_epu8(x, y); }
2533
0
    static inline T MinOrMax(T x, T y) { return std::min(x, y); }
2534
};
2535
2536
struct SSEWrapperMaxByte
2537
{
2538
    using T = uint8_t;
2539
    typedef __m128i Vec;
2540
2541
0
    static inline Vec LoadU(const T *x) { return _mm_loadu_si128(reinterpret_cast<const Vec*>(x)); }
2542
0
    static inline void StoreU(T *x, Vec y) { _mm_storeu_si128(reinterpret_cast<Vec*>(x), y); }
2543
0
    static inline Vec MinOrMax(Vec x, Vec y) { return _mm_max_epu8(x, y); }
2544
0
    static inline T MinOrMax(T x, T y) { return std::max(x, y); }
2545
};
2546
2547
struct SSEWrapperMinUInt16
2548
{
2549
    using T = uint16_t;
2550
    typedef __m128i Vec;
2551
2552
0
    static inline Vec LoadU(const T *x) { return _mm_loadu_si128(reinterpret_cast<const Vec*>(x)); }
2553
0
    static inline void StoreU(T *x, Vec y) { _mm_storeu_si128(reinterpret_cast<Vec*>(x), y); }
2554
#if defined(__SSE4_1__) || defined(USE_NEON_OPTIMIZATIONS)
2555
    static inline Vec MinOrMax(Vec x, Vec y) { return _mm_min_epu16(x, y); }
2556
#else
2557
0
    static inline Vec MinOrMax(Vec x, Vec y) { return
2558
0
        _mm_add_epi16(
2559
0
           _mm_min_epi16(
2560
0
             _mm_add_epi16(x, _mm_set1_epi16(-32768)),
2561
0
             _mm_add_epi16(y, _mm_set1_epi16(-32768))),
2562
0
           _mm_set1_epi16(-32768)); }
2563
#endif
2564
0
    static inline T MinOrMax(T x, T y) { return std::min(x, y); }
2565
};
2566
2567
struct SSEWrapperMaxUInt16
2568
{
2569
    using T = uint16_t;
2570
    typedef __m128i Vec;
2571
2572
0
    static inline Vec LoadU(const T *x) { return _mm_loadu_si128(reinterpret_cast<const Vec*>(x)); }
2573
0
    static inline void StoreU(T *x, Vec y) { _mm_storeu_si128(reinterpret_cast<Vec*>(x), y); }
2574
#if defined(__SSE4_1__) || defined(USE_NEON_OPTIMIZATIONS)
2575
    static inline Vec MinOrMax(Vec x, Vec y) { return _mm_max_epu16(x, y); }
2576
#else
2577
0
    static inline Vec MinOrMax(Vec x, Vec y) { return
2578
0
        _mm_add_epi16(
2579
0
           _mm_max_epi16(
2580
0
             _mm_add_epi16(x, _mm_set1_epi16(-32768)),
2581
0
             _mm_add_epi16(y, _mm_set1_epi16(-32768))),
2582
0
           _mm_set1_epi16(-32768)); }
2583
#endif
2584
0
    static inline T MinOrMax(T x, T y) { return std::max(x, y); }
2585
};
2586
2587
struct SSEWrapperMinInt16
2588
{
2589
    using T = int16_t;
2590
    typedef __m128i Vec;
2591
2592
0
    static inline Vec LoadU(const T *x) { return _mm_loadu_si128(reinterpret_cast<const Vec*>(x)); }
2593
0
    static inline void StoreU(T *x, Vec y) { _mm_storeu_si128(reinterpret_cast<Vec*>(x), y); }
2594
0
    static inline Vec MinOrMax(Vec x, Vec y) { return _mm_min_epi16(x, y); }
2595
0
    static inline T MinOrMax(T x, T y) { return std::min(x, y); }
2596
};
2597
2598
struct SSEWrapperMaxInt16
2599
{
2600
    using T = int16_t;
2601
    typedef __m128i Vec;
2602
2603
0
    static inline Vec LoadU(const T *x) { return _mm_loadu_si128(reinterpret_cast<const Vec*>(x)); }
2604
0
    static inline void StoreU(T *x, Vec y) { _mm_storeu_si128(reinterpret_cast<Vec*>(x), y); }
2605
0
    static inline Vec MinOrMax(Vec x, Vec y) { return _mm_max_epi16(x, y); }
2606
0
    static inline T MinOrMax(T x, T y) { return std::max(x, y); }
2607
};
2608
2609
struct SSEWrapperMinFloat
2610
{
2611
    using T = float;
2612
    typedef __m128 Vec;
2613
2614
0
    static inline Vec LoadU(const T *x) { return _mm_loadu_ps(x); }
2615
0
    static inline void StoreU(T *x, Vec y) { _mm_storeu_ps(x, y); }
2616
0
    static inline Vec MinOrMax(Vec x, Vec y) { return _mm_min_ps(x, y); }
2617
0
    static inline T MinOrMax(T x, T y) { return std::min(x, y); }
2618
};
2619
2620
struct SSEWrapperMaxFloat
2621
{
2622
    using T = float;
2623
    typedef __m128 Vec;
2624
2625
0
    static inline Vec LoadU(const T *x) { return _mm_loadu_ps(x); }
2626
0
    static inline void StoreU(T *x, Vec y) { _mm_storeu_ps(x, y); }
2627
0
    static inline Vec MinOrMax(Vec x, Vec y) { return _mm_max_ps(x, y); }
2628
0
    static inline T MinOrMax(T x, T y) { return std::max(x, y); }
2629
};
2630
2631
struct SSEWrapperMinDouble
2632
{
2633
    using T = double;
2634
    typedef __m128d Vec;
2635
2636
0
    static inline Vec LoadU(const T *x) { return _mm_loadu_pd(x); }
2637
0
    static inline void StoreU(T *x, Vec y) { _mm_storeu_pd(x, y); }
2638
0
    static inline Vec MinOrMax(Vec x, Vec y) { return _mm_min_pd(x, y); }
2639
0
    static inline T MinOrMax(T x, T y) { return std::min(x, y); }
2640
};
2641
2642
struct SSEWrapperMaxDouble
2643
{
2644
    using T = double;
2645
    typedef __m128d Vec;
2646
2647
0
    static inline Vec LoadU(const T *x) { return _mm_loadu_pd(x); }
2648
0
    static inline void StoreU(T *x, Vec y) { _mm_storeu_pd(x, y); }
2649
0
    static inline Vec MinOrMax(Vec x, Vec y) { return _mm_max_pd(x, y); }
2650
0
    static inline T MinOrMax(T x, T y) { return std::max(x, y); }
2651
};
2652
2653
}  // namespace
2654
2655
// clang-format on
2656
2657
#endif  // USE_SSE2
2658
2659
template <typename ReturnType>
2660
static CPLErr MinPixelFunc(void **papoSources, int nSources, void *pData,
2661
                           int nXSize, int nYSize, GDALDataType eSrcType,
2662
                           GDALDataType eBufType, int nPixelSpace,
2663
                           int nLineSpace, CSLConstList papszArgs)
2664
0
{
2665
0
    struct Comparator
2666
0
    {
2667
0
        static bool compare(double x, double resVal)
2668
0
        {
2669
            // Written this way to deal with resVal being NaN
2670
0
            return !(x >= resVal);
2671
0
        }
Unexecuted instantiation: pixelfunctions.cpp:MinPixelFunc<(anonymous namespace)::ReturnValue>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)::Comparator::compare(double, double)
Unexecuted instantiation: pixelfunctions.cpp:MinPixelFunc<(anonymous namespace)::ReturnIndex>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)::Comparator::compare(double, double)
2672
0
    };
2673
2674
0
    double dfK = std::numeric_limits<double>::quiet_NaN();
2675
    if constexpr (std::is_same_v<ReturnType, ReturnValue>)
2676
0
    {
2677
0
        if (FetchDoubleArg(papszArgs, "k", &dfK, &dfK) != CE_None)
2678
0
            return CE_Failure;
2679
2680
0
#ifdef USE_SSE2
2681
0
        const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
2682
0
        if (std::isnan(dfK) && nSources > 0 && !bHasNoData &&
2683
0
            eSrcType == eBufType &&
2684
0
            nPixelSpace == GDALGetDataTypeSizeBytes(eSrcType))
2685
0
        {
2686
0
            if (eSrcType == GDT_Byte)
2687
0
            {
2688
0
                OptimizedMinOrMaxSSE2<uint8_t, SSEWrapperMinByte>(
2689
0
                    papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
2690
0
                return CE_None;
2691
0
            }
2692
0
            else if (eSrcType == GDT_UInt16)
2693
0
            {
2694
0
                OptimizedMinOrMaxSSE2<uint16_t, SSEWrapperMinUInt16>(
2695
0
                    papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
2696
0
                return CE_None;
2697
0
            }
2698
0
            else if (eSrcType == GDT_Int16)
2699
0
            {
2700
0
                OptimizedMinOrMaxSSE2<int16_t, SSEWrapperMinInt16>(
2701
0
                    papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
2702
0
                return CE_None;
2703
0
            }
2704
0
            else if (eSrcType == GDT_Float32)
2705
0
            {
2706
0
                OptimizedMinOrMaxSSE2<float, SSEWrapperMinFloat>(
2707
0
                    papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
2708
0
                return CE_None;
2709
0
            }
2710
0
            else if (eSrcType == GDT_Float64)
2711
0
            {
2712
0
                OptimizedMinOrMaxSSE2<double, SSEWrapperMinDouble>(
2713
0
                    papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
2714
0
                return CE_None;
2715
0
            }
2716
0
        }
2717
0
#endif
2718
0
    }
2719
2720
0
    return MinOrMaxPixelFunc<Comparator, ReturnType>(
2721
0
        dfK, papoSources, nSources, pData, nXSize, nYSize, eSrcType, eBufType,
2722
0
        nPixelSpace, nLineSpace, papszArgs);
2723
0
}
Unexecuted instantiation: pixelfunctions.cpp:CPLErr MinPixelFunc<(anonymous namespace)::ReturnValue>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)
Unexecuted instantiation: pixelfunctions.cpp:CPLErr MinPixelFunc<(anonymous namespace)::ReturnIndex>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)
2724
2725
template <typename ReturnType>
2726
static CPLErr MaxPixelFunc(void **papoSources, int nSources, void *pData,
2727
                           int nXSize, int nYSize, GDALDataType eSrcType,
2728
                           GDALDataType eBufType, int nPixelSpace,
2729
                           int nLineSpace, CSLConstList papszArgs)
2730
0
{
2731
0
    struct Comparator
2732
0
    {
2733
0
        static bool compare(double x, double resVal)
2734
0
        {
2735
            // Written this way to deal with resVal being NaN
2736
0
            return !(x <= resVal);
2737
0
        }
Unexecuted instantiation: pixelfunctions.cpp:MaxPixelFunc<(anonymous namespace)::ReturnValue>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)::Comparator::compare(double, double)
Unexecuted instantiation: pixelfunctions.cpp:MaxPixelFunc<(anonymous namespace)::ReturnIndex>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)::Comparator::compare(double, double)
2738
0
    };
2739
2740
0
    double dfK = std::numeric_limits<double>::quiet_NaN();
2741
    if constexpr (std::is_same_v<ReturnType, ReturnValue>)
2742
0
    {
2743
0
        if (FetchDoubleArg(papszArgs, "k", &dfK, &dfK) != CE_None)
2744
0
            return CE_Failure;
2745
2746
0
#ifdef USE_SSE2
2747
0
        const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
2748
0
        if (std::isnan(dfK) && nSources > 0 && !bHasNoData &&
2749
0
            eSrcType == eBufType &&
2750
0
            nPixelSpace == GDALGetDataTypeSizeBytes(eSrcType))
2751
0
        {
2752
0
            if (eSrcType == GDT_Byte)
2753
0
            {
2754
0
                OptimizedMinOrMaxSSE2<uint8_t, SSEWrapperMaxByte>(
2755
0
                    papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
2756
0
                return CE_None;
2757
0
            }
2758
0
            else if (eSrcType == GDT_UInt16)
2759
0
            {
2760
0
                OptimizedMinOrMaxSSE2<uint16_t, SSEWrapperMaxUInt16>(
2761
0
                    papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
2762
0
                return CE_None;
2763
0
            }
2764
0
            else if (eSrcType == GDT_Int16)
2765
0
            {
2766
0
                OptimizedMinOrMaxSSE2<int16_t, SSEWrapperMaxInt16>(
2767
0
                    papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
2768
0
                return CE_None;
2769
0
            }
2770
0
            else if (eSrcType == GDT_Float32)
2771
0
            {
2772
0
                OptimizedMinOrMaxSSE2<float, SSEWrapperMaxFloat>(
2773
0
                    papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
2774
0
                return CE_None;
2775
0
            }
2776
0
            else if (eSrcType == GDT_Float64)
2777
0
            {
2778
0
                OptimizedMinOrMaxSSE2<double, SSEWrapperMaxDouble>(
2779
0
                    papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
2780
0
                return CE_None;
2781
0
            }
2782
0
        }
2783
0
#endif
2784
0
    }
2785
2786
0
    return MinOrMaxPixelFunc<Comparator, ReturnType>(
2787
0
        dfK, papoSources, nSources, pData, nXSize, nYSize, eSrcType, eBufType,
2788
0
        nPixelSpace, nLineSpace, papszArgs);
2789
0
}
Unexecuted instantiation: pixelfunctions.cpp:CPLErr MaxPixelFunc<(anonymous namespace)::ReturnValue>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)
Unexecuted instantiation: pixelfunctions.cpp:CPLErr MaxPixelFunc<(anonymous namespace)::ReturnIndex>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)
2790
2791
static const char pszExprPixelFuncMetadata[] =
2792
    "<PixelFunctionArgumentsList>"
2793
    "   <Argument type='builtin' value='NoData' optional='true' />"
2794
    "   <Argument name='propagateNoData' description='Whether the output value "
2795
    "should be NoData as as soon as one source is NoData' type='boolean' "
2796
    "default='false' />"
2797
    "   <Argument name='expression' "
2798
    "             description='Expression to be evaluated' "
2799
    "             type='string'></Argument>"
2800
    "   <Argument name='dialect' "
2801
    "             description='Expression dialect' "
2802
    "             type='string-select'"
2803
    "             default='muparser'>"
2804
    "       <Value>exprtk</Value>"
2805
    "       <Value>muparser</Value>"
2806
    "   </Argument>"
2807
    "   <Argument type='builtin' value='source_names' />"
2808
    "   <Argument type='builtin' value='xoff' />"
2809
    "   <Argument type='builtin' value='yoff' />"
2810
    "   <Argument type='builtin' value='geotransform' />"
2811
    "</PixelFunctionArgumentsList>";
2812
2813
static CPLErr ExprPixelFunc(void **papoSources, int nSources, void *pData,
2814
                            int nXSize, int nYSize, GDALDataType eSrcType,
2815
                            GDALDataType eBufType, int nPixelSpace,
2816
                            int nLineSpace, CSLConstList papszArgs)
2817
0
{
2818
    /* ---- Init ---- */
2819
0
    if (GDALDataTypeIsComplex(eSrcType))
2820
0
    {
2821
0
        CPLError(CE_Failure, CPLE_AppDefined,
2822
0
                 "expression cannot by applied to complex data types");
2823
0
        return CE_Failure;
2824
0
    }
2825
2826
0
    double dfNoData{0};
2827
0
    const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
2828
0
    if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)
2829
0
        return CE_Failure;
2830
2831
0
    const bool bPropagateNoData = CPLTestBool(
2832
0
        CSLFetchNameValueDef(papszArgs, "propagateNoData", "false"));
2833
2834
0
    const char *pszExpression = CSLFetchNameValue(papszArgs, "expression");
2835
0
    if (!pszExpression)
2836
0
    {
2837
0
        CPLError(CE_Failure, CPLE_AppDefined,
2838
0
                 "Missing 'expression' pixel function argument");
2839
0
        return CE_Failure;
2840
0
    }
2841
2842
0
    const char *pszSourceNames = CSLFetchNameValue(papszArgs, "source_names");
2843
0
    const CPLStringList aosSourceNames(
2844
0
        CSLTokenizeString2(pszSourceNames, "|", 0));
2845
0
    if (aosSourceNames.size() != nSources)
2846
0
    {
2847
0
        CPLError(CE_Failure, CPLE_AppDefined,
2848
0
                 "The source_names variable passed to ExprPixelFunc() has %d "
2849
0
                 "values, whereas %d were expected. An invalid variable name "
2850
0
                 "has likely been used",
2851
0
                 aosSourceNames.size(), nSources);
2852
0
        return CE_Failure;
2853
0
    }
2854
2855
0
    std::vector<double> adfValuesForPixel(nSources);
2856
2857
0
    const char *pszDialect = CSLFetchNameValue(papszArgs, "dialect");
2858
0
    if (!pszDialect)
2859
0
    {
2860
0
        pszDialect = "muparser";
2861
0
    }
2862
2863
0
    auto poExpression = gdal::MathExpression::Create(pszExpression, pszDialect);
2864
2865
    // cppcheck-suppress knownConditionTrueFalse
2866
0
    if (!poExpression)
2867
0
    {
2868
0
        return CE_Failure;
2869
0
    }
2870
2871
0
    int nXOff = 0;
2872
0
    int nYOff = 0;
2873
0
    GDALGeoTransform gt;
2874
0
    double dfCenterX = 0;
2875
0
    double dfCenterY = 0;
2876
2877
0
    bool includeCenterCoords = false;
2878
0
    if (strstr(pszExpression, "_CENTER_X_") ||
2879
0
        strstr(pszExpression, "_CENTER_Y_"))
2880
0
    {
2881
0
        includeCenterCoords = true;
2882
2883
0
        const char *pszXOff = CSLFetchNameValue(papszArgs, "xoff");
2884
0
        nXOff = std::atoi(pszXOff);
2885
2886
0
        const char *pszYOff = CSLFetchNameValue(papszArgs, "yoff");
2887
0
        nYOff = std::atoi(pszYOff);
2888
2889
0
        const char *pszGT = CSLFetchNameValue(papszArgs, "geotransform");
2890
0
        if (pszGT == nullptr)
2891
0
        {
2892
0
            CPLError(CE_Failure, CPLE_AppDefined,
2893
0
                     "To use _CENTER_X_ or _CENTER_Y_ in an expression, "
2894
0
                     "VRTDataset must have a <GeoTransform> element.");
2895
0
            return CE_Failure;
2896
0
        }
2897
2898
0
        CPLStringList aosGeoTransform(
2899
0
            CSLTokenizeString2(pszGT, ",", CSLT_HONOURSTRINGS));
2900
0
        if (aosGeoTransform.size() != 6)
2901
0
        {
2902
0
            CPLError(CE_Failure, CPLE_AppDefined,
2903
0
                     "Invalid GeoTransform argument");
2904
0
            return CE_Failure;
2905
0
        }
2906
0
        for (int i = 0; i < 6; i++)
2907
0
        {
2908
0
            gt[i] = CPLAtof(aosGeoTransform[i]);
2909
0
        }
2910
0
    }
2911
2912
0
    {
2913
0
        int iSource = 0;
2914
0
        for (const auto &osName : aosSourceNames)
2915
0
        {
2916
0
            poExpression->RegisterVariable(osName,
2917
0
                                           &adfValuesForPixel[iSource++]);
2918
0
        }
2919
0
    }
2920
2921
0
    if (includeCenterCoords)
2922
0
    {
2923
0
        poExpression->RegisterVariable("_CENTER_X_", &dfCenterX);
2924
0
        poExpression->RegisterVariable("_CENTER_Y_", &dfCenterY);
2925
0
    }
2926
2927
0
    if (bHasNoData)
2928
0
    {
2929
0
        poExpression->RegisterVariable("NODATA", &dfNoData);
2930
0
    }
2931
2932
0
    if (strstr(pszExpression, "BANDS"))
2933
0
    {
2934
0
        poExpression->RegisterVector("BANDS", &adfValuesForPixel);
2935
0
    }
2936
2937
0
    std::unique_ptr<double, VSIFreeReleaser> padfResults(
2938
0
        static_cast<double *>(VSI_MALLOC2_VERBOSE(nXSize, sizeof(double))));
2939
0
    if (!padfResults)
2940
0
        return CE_Failure;
2941
2942
    /* ---- Set pixels ---- */
2943
0
    size_t ii = 0;
2944
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
2945
0
    {
2946
0
        for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
2947
0
        {
2948
0
            double &dfResult = padfResults.get()[iCol];
2949
0
            bool resultIsNoData = false;
2950
2951
0
            for (int iSrc = 0; iSrc < nSources; iSrc++)
2952
0
            {
2953
                // cppcheck-suppress unreadVariable
2954
0
                double dfVal = GetSrcVal(papoSources[iSrc], eSrcType, ii);
2955
2956
0
                if (bHasNoData && bPropagateNoData && IsNoData(dfVal, dfNoData))
2957
0
                {
2958
0
                    resultIsNoData = true;
2959
0
                }
2960
2961
0
                adfValuesForPixel[iSrc] = dfVal;
2962
0
            }
2963
2964
0
            if (includeCenterCoords)
2965
0
            {
2966
                // Add 0.5 to pixel / line to move from pixel corner to cell center
2967
0
                gt.Apply(static_cast<double>(iCol + nXOff) + 0.5,
2968
0
                         static_cast<double>(iLine + nYOff) + 0.5, &dfCenterX,
2969
0
                         &dfCenterY);
2970
0
            }
2971
2972
0
            if (resultIsNoData)
2973
0
            {
2974
0
                dfResult = dfNoData;
2975
0
            }
2976
0
            else
2977
0
            {
2978
0
                if (auto eErr = poExpression->Evaluate(); eErr != CE_None)
2979
0
                {
2980
0
                    return CE_Failure;
2981
0
                }
2982
2983
0
                dfResult = poExpression->Results()[0];
2984
0
            }
2985
0
        }
2986
2987
0
        GDALCopyWords(padfResults.get(), GDT_Float64, sizeof(double),
2988
0
                      static_cast<GByte *>(pData) +
2989
0
                          static_cast<GSpacing>(nLineSpace) * iLine,
2990
0
                      eBufType, nPixelSpace, nXSize);
2991
0
    }
2992
2993
    /* ---- Return success ---- */
2994
0
    return CE_None;
2995
0
}  // ExprPixelFunc
2996
2997
static const char pszReclassifyPixelFuncMetadata[] =
2998
    "<PixelFunctionArgumentsList>"
2999
    "   <Argument name='mapping' "
3000
    "             description='Lookup table for mapping, in format "
3001
    "from=to,from=to' "
3002
    "             type='string'></Argument>"
3003
    "   <Argument type='builtin' value='NoData' optional='true' />"
3004
    "</PixelFunctionArgumentsList>";
3005
3006
static CPLErr ReclassifyPixelFunc(void **papoSources, int nSources, void *pData,
3007
                                  int nXSize, int nYSize, GDALDataType eSrcType,
3008
                                  GDALDataType eBufType, int nPixelSpace,
3009
                                  int nLineSpace, CSLConstList papszArgs)
3010
0
{
3011
0
    if (GDALDataTypeIsComplex(eSrcType))
3012
0
    {
3013
0
        CPLError(CE_Failure, CPLE_AppDefined,
3014
0
                 "reclassify cannot by applied to complex data types");
3015
0
        return CE_Failure;
3016
0
    }
3017
3018
0
    if (nSources != 1)
3019
0
    {
3020
0
        CPLError(CE_Failure, CPLE_AppDefined,
3021
0
                 "reclassify only be applied to a single source at a time");
3022
0
        return CE_Failure;
3023
0
    }
3024
0
    std::optional<double> noDataValue{};
3025
3026
0
    const char *pszNoData = CSLFetchNameValue(papszArgs, "NoData");
3027
0
    if (pszNoData != nullptr)
3028
0
    {
3029
0
        noDataValue = CPLAtof(pszNoData);
3030
0
    }
3031
3032
0
    const char *pszMappings = CSLFetchNameValue(papszArgs, "mapping");
3033
0
    if (pszMappings == nullptr)
3034
0
    {
3035
0
        CPLError(CE_Failure, CPLE_AppDefined,
3036
0
                 "reclassify must be called with 'mapping' argument");
3037
0
        return CE_Failure;
3038
0
    }
3039
3040
0
    gdal::Reclassifier oReclassifier;
3041
0
    if (auto eErr = oReclassifier.Init(pszMappings, noDataValue, eBufType);
3042
0
        eErr != CE_None)
3043
0
    {
3044
0
        return eErr;
3045
0
    }
3046
3047
0
    std::unique_ptr<double, VSIFreeReleaser> padfResults(
3048
0
        static_cast<double *>(VSI_MALLOC2_VERBOSE(nXSize, sizeof(double))));
3049
0
    if (!padfResults)
3050
0
        return CE_Failure;
3051
3052
0
    size_t ii = 0;
3053
0
    bool bSuccess = false;
3054
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
3055
0
    {
3056
0
        for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
3057
0
        {
3058
0
            double srcVal = GetSrcVal(papoSources[0], eSrcType, ii);
3059
0
            padfResults.get()[iCol] =
3060
0
                oReclassifier.Reclassify(srcVal, bSuccess);
3061
0
            if (!bSuccess)
3062
0
            {
3063
0
                CPLError(CE_Failure, CPLE_AppDefined,
3064
0
                         "Encountered value %g with no specified mapping",
3065
0
                         srcVal);
3066
0
                return CE_Failure;
3067
0
            }
3068
0
        }
3069
3070
0
        GDALCopyWords(padfResults.get(), GDT_Float64, sizeof(double),
3071
0
                      static_cast<GByte *>(pData) +
3072
0
                          static_cast<GSpacing>(nLineSpace) * iLine,
3073
0
                      eBufType, nPixelSpace, nXSize);
3074
0
    }
3075
3076
0
    return CE_None;
3077
0
}  // ReclassifyPixelFunc
3078
3079
struct MeanKernel
3080
{
3081
    static constexpr const char *pszName = "mean";
3082
3083
    double dfMean = 0;
3084
    int nValidSources = 0;
3085
3086
    void Reset()
3087
0
    {
3088
0
        dfMean = 0;
3089
0
        nValidSources = 0;
3090
0
    }
3091
3092
    static CPLErr ProcessArguments(CSLConstList)
3093
0
    {
3094
0
        return CE_None;
3095
0
    }
3096
3097
    void ProcessPixel(double dfVal)
3098
0
    {
3099
0
        ++nValidSources;
3100
3101
0
        if (CPL_UNLIKELY(std::isinf(dfVal)))
3102
0
        {
3103
0
            if (nValidSources == 1)
3104
0
            {
3105
0
                dfMean = dfVal;
3106
0
            }
3107
0
            else if (dfVal == -dfMean)
3108
0
            {
3109
0
                dfMean = std::numeric_limits<double>::quiet_NaN();
3110
0
            }
3111
0
        }
3112
0
        else if (CPL_UNLIKELY(std::isinf(dfMean)))
3113
0
        {
3114
0
            if (!std::isfinite(dfVal))
3115
0
            {
3116
0
                dfMean = std::numeric_limits<double>::quiet_NaN();
3117
0
            }
3118
0
        }
3119
0
        else
3120
0
        {
3121
0
            const double delta = dfVal - dfMean;
3122
0
            if (CPL_UNLIKELY(std::isinf(delta)))
3123
0
                dfMean += dfVal / nValidSources - dfMean / nValidSources;
3124
0
            else
3125
0
                dfMean += delta / nValidSources;
3126
0
        }
3127
0
    }
3128
3129
    bool HasValue() const
3130
0
    {
3131
0
        return nValidSources > 0;
3132
0
    }
3133
3134
    double GetValue() const
3135
0
    {
3136
0
        return dfMean;
3137
0
    }
3138
};
3139
3140
struct GeoMeanKernel
3141
{
3142
    static constexpr const char *pszName = "geometric_mean";
3143
3144
    double dfProduct = 1;
3145
    int nValidSources = 0;
3146
3147
    void Reset()
3148
0
    {
3149
0
        dfProduct = 1;
3150
0
        nValidSources = 0;
3151
0
    }
3152
3153
    static CPLErr ProcessArguments(CSLConstList)
3154
0
    {
3155
0
        return CE_None;
3156
0
    }
3157
3158
    void ProcessPixel(double dfVal)
3159
0
    {
3160
0
        dfProduct *= dfVal;
3161
0
        nValidSources++;
3162
0
    }
3163
3164
    bool HasValue() const
3165
0
    {
3166
0
        return nValidSources > 0;
3167
0
    }
3168
3169
    double GetValue() const
3170
0
    {
3171
0
        return std::pow(dfProduct, 1.0 / nValidSources);
3172
0
    }
3173
};
3174
3175
struct HarmonicMeanKernel
3176
{
3177
    static constexpr const char *pszName = "harmonic_mean";
3178
3179
    double dfDenom = 0;
3180
    int nValidSources = 0;
3181
    bool bValueIsZero = false;
3182
    bool bPropagateZero = false;
3183
3184
    void Reset()
3185
0
    {
3186
0
        dfDenom = 0;
3187
0
        nValidSources = 0;
3188
0
        bValueIsZero = false;
3189
0
    }
3190
3191
    void ProcessPixel(double dfVal)
3192
0
    {
3193
0
        if (dfVal == 0)
3194
0
        {
3195
0
            bValueIsZero = true;
3196
0
        }
3197
0
        else
3198
0
        {
3199
0
            dfDenom += 1 / dfVal;
3200
0
        }
3201
0
        nValidSources++;
3202
0
    }
3203
3204
    CPLErr ProcessArguments(CSLConstList papszArgs)
3205
0
    {
3206
0
        bPropagateZero =
3207
0
            CPLTestBool(CSLFetchNameValueDef(papszArgs, "propagateZero", "0"));
3208
0
        return CE_None;
3209
0
    }
3210
3211
    bool HasValue() const
3212
0
    {
3213
0
        return dfDenom > 0 && (bPropagateZero || !bValueIsZero);
3214
0
    }
3215
3216
    double GetValue() const
3217
0
    {
3218
0
        if (bPropagateZero && bValueIsZero)
3219
0
        {
3220
0
            return 0;
3221
0
        }
3222
0
        return static_cast<double>(nValidSources) / dfDenom;
3223
0
    }
3224
};
3225
3226
struct MedianKernel
3227
{
3228
    static constexpr const char *pszName = "median";
3229
3230
    mutable std::vector<double> values{};
3231
3232
    void Reset()
3233
0
    {
3234
0
        values.clear();
3235
0
    }
3236
3237
    static CPLErr ProcessArguments(CSLConstList)
3238
0
    {
3239
0
        return CE_None;
3240
0
    }
3241
3242
    void ProcessPixel(double dfVal)
3243
0
    {
3244
0
        if (!std::isnan(dfVal))
3245
0
        {
3246
0
            values.push_back(dfVal);
3247
0
        }
3248
0
    }
3249
3250
    bool HasValue() const
3251
0
    {
3252
0
        return !values.empty();
3253
0
    }
3254
3255
    double GetValue() const
3256
0
    {
3257
0
        std::sort(values.begin(), values.end());
3258
0
        if (values.size() % 2 == 0)
3259
0
        {
3260
0
            return 0.5 *
3261
0
                   (values[values.size() / 2 - 1] + values[values.size() / 2]);
3262
0
        }
3263
3264
0
        return values[values.size() / 2];
3265
0
    }
3266
};
3267
3268
struct ModeKernel
3269
{
3270
    static constexpr const char *pszName = "mode";
3271
3272
    std::map<double, size_t> counts{};
3273
    std::size_t nanCount{0};
3274
    double dfMax = std::numeric_limits<double>::quiet_NaN();
3275
    decltype(counts.begin()) oMax = counts.end();
3276
3277
    void Reset()
3278
0
    {
3279
0
        nanCount = 0;
3280
0
        counts.clear();
3281
0
        oMax = counts.end();
3282
0
    }
3283
3284
    static CPLErr ProcessArguments(CSLConstList)
3285
0
    {
3286
0
        return CE_None;
3287
0
    }
3288
3289
    void ProcessPixel(double dfVal)
3290
0
    {
3291
0
        if (std::isnan(dfVal))
3292
0
        {
3293
0
            nanCount += 1;
3294
0
            return;
3295
0
        }
3296
3297
        // if dfVal is NaN, try_emplace will return an entry for a different key!
3298
0
        auto [it, inserted] = counts.try_emplace(dfVal, 0);
3299
3300
0
        it->second += 1;
3301
3302
0
        if (oMax == counts.end() || it->second > oMax->second)
3303
0
        {
3304
0
            oMax = it;
3305
0
        }
3306
0
    }
3307
3308
    bool HasValue() const
3309
0
    {
3310
0
        return nanCount > 0 || oMax != counts.end();
3311
0
    }
3312
3313
    double GetValue() const
3314
0
    {
3315
0
        double ret = std::numeric_limits<double>::quiet_NaN();
3316
0
        if (oMax != counts.end())
3317
0
        {
3318
0
            const size_t nCount = oMax->second;
3319
0
            if (nCount > nanCount)
3320
0
                ret = oMax->first;
3321
0
        }
3322
0
        return ret;
3323
0
    }
3324
};
3325
3326
static const char pszBasicPixelFuncMetadata[] =
3327
    "<PixelFunctionArgumentsList>"
3328
    "   <Argument type='builtin' value='NoData' optional='true' />"
3329
    "   <Argument name='propagateNoData' description='Whether the output value "
3330
    "should be NoData as as soon as one source is NoData' type='boolean' "
3331
    "default='false' />"
3332
    "</PixelFunctionArgumentsList>";
3333
3334
#if defined(USE_SSE2) && !defined(USE_NEON_OPTIMIZATIONS)
3335
inline __m128i packus_epi32(__m128i low, __m128i high)
3336
0
{
3337
#if __SSE4_1__
3338
    return _mm_packus_epi32(low, high);  // Pack uint32 to uint16
3339
#else
3340
0
    low = _mm_add_epi32(low, _mm_set1_epi32(-32768));
3341
0
    high = _mm_add_epi32(high, _mm_set1_epi32(-32768));
3342
0
    return _mm_sub_epi16(_mm_packs_epi32(low, high), _mm_set1_epi16(-32768));
3343
0
#endif
3344
0
}
3345
#endif
3346
3347
#ifdef USE_SSE2
3348
3349
template <class T, class SSEWrapper>
3350
static void OptimizedMeanFloatSSE2(const void *const *papoSources, int nSources,
3351
                                   void *pData, int nXSize, int nYSize,
3352
                                   int nLineSpace)
3353
0
{
3354
0
    assert(nSources >= 1);
3355
0
    constexpr int VALUES_PER_REG =
3356
0
        static_cast<int>(sizeof(typename SSEWrapper::Vec) / sizeof(T));
3357
0
    const T invSources = static_cast<T>(1.0) / static_cast<T>(nSources);
3358
0
    const auto invSourcesSSE = SSEWrapper::Set1(invSources);
3359
0
    const auto signMaskSSE = SSEWrapper::Set1(static_cast<T>(-0.0));
3360
0
    const auto infSSE = SSEWrapper::Set1(std::numeric_limits<T>::infinity());
3361
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
3362
0
    {
3363
0
        T *CPL_RESTRICT pDest =
3364
0
            reinterpret_cast<T *>(static_cast<GByte *>(pData) +
3365
0
                                  static_cast<GSpacing>(nLineSpace) * iLine);
3366
0
        const size_t iOffsetLine = static_cast<size_t>(iLine) * nXSize;
3367
0
        int iCol = 0;
3368
0
        for (; iCol < nXSize - (2 * VALUES_PER_REG - 1);
3369
0
             iCol += 2 * VALUES_PER_REG)
3370
0
        {
3371
0
            auto reg0 = SSEWrapper::LoadU(
3372
0
                static_cast<const T * CPL_RESTRICT>(papoSources[0]) +
3373
0
                iOffsetLine + iCol);
3374
0
            auto reg1 = SSEWrapper::LoadU(
3375
0
                static_cast<const T * CPL_RESTRICT>(papoSources[0]) +
3376
0
                iOffsetLine + iCol + VALUES_PER_REG);
3377
0
            for (int iSrc = 1; iSrc < nSources; ++iSrc)
3378
0
            {
3379
0
                const auto inputVal0 = SSEWrapper::LoadU(
3380
0
                    static_cast<const T * CPL_RESTRICT>(papoSources[iSrc]) +
3381
0
                    iOffsetLine + iCol);
3382
0
                const auto inputVal1 = SSEWrapper::LoadU(
3383
0
                    static_cast<const T * CPL_RESTRICT>(papoSources[iSrc]) +
3384
0
                    iOffsetLine + iCol + VALUES_PER_REG);
3385
0
                reg0 = SSEWrapper::Add(reg0, inputVal0);
3386
0
                reg1 = SSEWrapper::Add(reg1, inputVal1);
3387
0
            }
3388
0
            reg0 = SSEWrapper::Mul(reg0, invSourcesSSE);
3389
0
            reg1 = SSEWrapper::Mul(reg1, invSourcesSSE);
3390
3391
            // Detect infinity that could happen when summing huge
3392
            // values
3393
0
            if (SSEWrapper::MoveMask(SSEWrapper::Or(
3394
0
                    SSEWrapper::CmpEq(SSEWrapper::AndNot(signMaskSSE, reg0),
3395
0
                                      infSSE),
3396
0
                    SSEWrapper::CmpEq(SSEWrapper::AndNot(signMaskSSE, reg1),
3397
0
                                      infSSE))))
3398
0
            {
3399
0
                break;
3400
0
            }
3401
3402
0
            SSEWrapper::StoreU(pDest + iCol, reg0);
3403
0
            SSEWrapper::StoreU(pDest + iCol + VALUES_PER_REG, reg1);
3404
0
        }
3405
3406
        // Use numerically stable mean computation
3407
0
        for (; iCol < nXSize; ++iCol)
3408
0
        {
3409
0
            T mean = static_cast<const T * CPL_RESTRICT>(
3410
0
                papoSources[0])[iOffsetLine + iCol];
3411
0
            if (nSources >= 2)
3412
0
            {
3413
0
                T new_val = static_cast<const T * CPL_RESTRICT>(
3414
0
                    papoSources[1])[iOffsetLine + iCol];
3415
0
                if (CPL_UNLIKELY(std::isinf(new_val)))
3416
0
                {
3417
0
                    if (new_val == -mean)
3418
0
                    {
3419
0
                        pDest[iCol] = std::numeric_limits<T>::quiet_NaN();
3420
0
                        continue;
3421
0
                    }
3422
0
                }
3423
0
                else if (CPL_UNLIKELY(std::isinf(mean)))
3424
0
                {
3425
0
                    if (!std::isfinite(new_val))
3426
0
                    {
3427
0
                        pDest[iCol] = std::numeric_limits<T>::quiet_NaN();
3428
0
                        continue;
3429
0
                    }
3430
0
                }
3431
0
                else
3432
0
                {
3433
0
                    const T delta = new_val - mean;
3434
0
                    if (CPL_UNLIKELY(std::isinf(delta)))
3435
0
                        mean += new_val * static_cast<T>(0.5) -
3436
0
                                mean * static_cast<T>(0.5);
3437
0
                    else
3438
0
                        mean += delta * static_cast<T>(0.5);
3439
0
                }
3440
3441
0
                for (int iSrc = 2; iSrc < nSources; ++iSrc)
3442
0
                {
3443
0
                    new_val = static_cast<const T * CPL_RESTRICT>(
3444
0
                        papoSources[iSrc])[iOffsetLine + iCol];
3445
0
                    if (CPL_UNLIKELY(std::isinf(new_val)))
3446
0
                    {
3447
0
                        if (new_val == -mean)
3448
0
                        {
3449
0
                            mean = std::numeric_limits<T>::quiet_NaN();
3450
0
                            break;
3451
0
                        }
3452
0
                    }
3453
0
                    else if (CPL_UNLIKELY(std::isinf(mean)))
3454
0
                    {
3455
0
                        if (!std::isfinite(new_val))
3456
0
                        {
3457
0
                            mean = std::numeric_limits<T>::quiet_NaN();
3458
0
                            break;
3459
0
                        }
3460
0
                    }
3461
0
                    else
3462
0
                    {
3463
0
                        const T delta = new_val - mean;
3464
0
                        if (CPL_UNLIKELY(std::isinf(delta)))
3465
0
                            mean += new_val / static_cast<T>(iSrc + 1) -
3466
0
                                    mean / static_cast<T>(iSrc + 1);
3467
0
                        else
3468
0
                            mean += delta / static_cast<T>(iSrc + 1);
3469
0
                    }
3470
0
                }
3471
0
            }
3472
0
            pDest[iCol] = mean;
3473
0
        }
3474
0
    }
3475
0
}
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedMeanFloatSSE2<float, (anonymous namespace)::SSEWrapperFloat>(void const* const*, int, void*, int, int, int)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedMeanFloatSSE2<double, (anonymous namespace)::SSEWrapperDouble>(void const* const*, int, void*, int, int, int)
3476
3477
// clang-format off
3478
namespace
3479
{
3480
#ifdef __AVX2__
3481
struct SSEWrapperFloat
3482
{
3483
    typedef __m256 Vec;
3484
3485
    static inline Vec Set1(float x) { return _mm256_set1_ps(x); }
3486
    static inline Vec LoadU(const float *x) { return _mm256_loadu_ps(x); }
3487
    static inline void StoreU(float *x, Vec y) { _mm256_storeu_ps(x, y); }
3488
    static inline Vec Add(Vec x, Vec y) { return _mm256_add_ps(x, y); }
3489
    static inline Vec Mul(Vec x, Vec y) { return _mm256_mul_ps(x, y); }
3490
    static inline Vec Or(Vec x, Vec y) { return _mm256_or_ps(x, y); }
3491
    static inline Vec AndNot(Vec x, Vec y) { return _mm256_andnot_ps(x, y); }
3492
    static inline Vec CmpEq(Vec x, Vec y) { return _mm256_cmp_ps(x, y, _CMP_EQ_OQ); }
3493
    static inline int MoveMask(Vec x) { return _mm256_movemask_ps(x); }
3494
};
3495
3496
struct SSEWrapperDouble
3497
{
3498
    typedef __m256d Vec;
3499
3500
    static inline Vec Set1(double x) { return _mm256_set1_pd(x); }
3501
    static inline Vec LoadU(const double *x) { return _mm256_loadu_pd(x); }
3502
    static inline void StoreU(double *x, Vec y) { _mm256_storeu_pd(x, y); }
3503
    static inline Vec Add(Vec x, Vec y) { return _mm256_add_pd(x, y); }
3504
    static inline Vec Mul(Vec x, Vec y) { return _mm256_mul_pd(x, y); }
3505
    static inline Vec Or(Vec x, Vec y) { return _mm256_or_pd(x, y); }
3506
    static inline Vec AndNot(Vec x, Vec y) { return _mm256_andnot_pd(x, y); }
3507
    static inline Vec CmpEq(Vec x, Vec y) { return _mm256_cmp_pd(x, y, _CMP_EQ_OQ); }
3508
    static inline int MoveMask(Vec x) { return _mm256_movemask_pd(x); }
3509
};
3510
3511
#else
3512
3513
struct SSEWrapperFloat
3514
{
3515
    typedef __m128 Vec;
3516
3517
0
    static inline Vec Set1(float x) { return _mm_set1_ps(x); }
3518
0
    static inline Vec LoadU(const float *x) { return _mm_loadu_ps(x); }
3519
0
    static inline void StoreU(float *x, Vec y) { _mm_storeu_ps(x, y); }
3520
0
    static inline Vec Add(Vec x, Vec y) { return _mm_add_ps(x, y); }
3521
0
    static inline Vec Mul(Vec x, Vec y) { return _mm_mul_ps(x, y); }
3522
0
    static inline Vec Or(Vec x, Vec y) { return _mm_or_ps(x, y); }
3523
0
    static inline Vec AndNot(Vec x, Vec y) { return _mm_andnot_ps(x, y); }
3524
0
    static inline Vec CmpEq(Vec x, Vec y) { return _mm_cmpeq_ps(x, y); }
3525
0
    static inline int MoveMask(Vec x) { return _mm_movemask_ps(x); }
3526
};
3527
3528
struct SSEWrapperDouble
3529
{
3530
    typedef __m128d Vec;
3531
3532
0
    static inline Vec Set1(double x) { return _mm_set1_pd(x); }
3533
0
    static inline Vec LoadU(const double *x) { return _mm_loadu_pd(x); }
3534
0
    static inline void StoreU(double *x, Vec y) { _mm_storeu_pd(x, y); }
3535
0
    static inline Vec Add(Vec x, Vec y) { return _mm_add_pd(x, y); }
3536
0
    static inline Vec Mul(Vec x, Vec y) { return _mm_mul_pd(x, y); }
3537
0
    static inline Vec Or(Vec x, Vec y) { return _mm_or_pd(x, y); }
3538
0
    static inline Vec AndNot(Vec x, Vec y) { return _mm_andnot_pd(x, y); }
3539
0
    static inline Vec CmpEq(Vec x, Vec y) { return _mm_cmpeq_pd(x, y); }
3540
0
    static inline int MoveMask(Vec x) { return _mm_movemask_pd(x); }
3541
};
3542
#endif
3543
}  // namespace
3544
3545
// clang-format on
3546
3547
#endif  // USE_SSE2
3548
3549
template <typename Kernel>
3550
static CPLErr BasicPixelFunc(void **papoSources, int nSources, void *pData,
3551
                             int nXSize, int nYSize, GDALDataType eSrcType,
3552
                             GDALDataType eBufType, int nPixelSpace,
3553
                             int nLineSpace, CSLConstList papszArgs)
3554
0
{
3555
    /* ---- Init ---- */
3556
0
    Kernel oKernel;
3557
3558
0
    if (GDALDataTypeIsComplex(eSrcType))
3559
0
    {
3560
0
        CPLError(CE_Failure, CPLE_AppDefined,
3561
0
                 "Complex data types not supported by %s", oKernel.pszName);
3562
0
        return CE_Failure;
3563
0
    }
3564
3565
0
    double dfNoData{0};
3566
0
    const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
3567
0
    if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)
3568
0
        return CE_Failure;
3569
3570
0
    const bool bPropagateNoData = CPLTestBool(
3571
0
        CSLFetchNameValueDef(papszArgs, "propagateNoData", "false"));
3572
3573
0
    if (oKernel.ProcessArguments(papszArgs) == CE_Failure)
3574
0
    {
3575
0
        return CE_Failure;
3576
0
    }
3577
3578
0
#if defined(USE_SSE2) && !defined(USE_NEON_OPTIMIZATIONS)
3579
    if constexpr (std::is_same_v<Kernel, MeanKernel>)
3580
0
    {
3581
0
        if (!bHasNoData && eSrcType == GDT_Byte && eBufType == GDT_Byte &&
3582
0
            nPixelSpace == 1 &&
3583
            // We use signed int16 to accumulate
3584
0
            nSources <= std::numeric_limits<int16_t>::max() /
3585
0
                            std::numeric_limits<uint8_t>::max())
3586
0
        {
3587
0
            using T = uint8_t;
3588
0
            constexpr int VALUES_PER_REG = 16;
3589
0
            if (nSources == 2)
3590
0
            {
3591
0
                for (int iLine = 0; iLine < nYSize; ++iLine)
3592
0
                {
3593
0
                    T *CPL_RESTRICT pDest = reinterpret_cast<T *>(
3594
0
                        static_cast<GByte *>(pData) +
3595
0
                        static_cast<GSpacing>(nLineSpace) * iLine);
3596
0
                    const size_t iOffsetLine =
3597
0
                        static_cast<size_t>(iLine) * nXSize;
3598
0
                    int iCol = 0;
3599
0
                    for (; iCol < nXSize - (VALUES_PER_REG - 1);
3600
0
                         iCol += VALUES_PER_REG)
3601
0
                    {
3602
0
                        const __m128i inputVal0 =
3603
0
                            _mm_loadu_si128(reinterpret_cast<const __m128i *>(
3604
0
                                static_cast<const T * CPL_RESTRICT>(
3605
0
                                    papoSources[0]) +
3606
0
                                iOffsetLine + iCol));
3607
0
                        const __m128i inputVal1 =
3608
0
                            _mm_loadu_si128(reinterpret_cast<const __m128i *>(
3609
0
                                static_cast<const T * CPL_RESTRICT>(
3610
0
                                    papoSources[1]) +
3611
0
                                iOffsetLine + iCol));
3612
0
                        _mm_storeu_si128(
3613
0
                            reinterpret_cast<__m128i *>(pDest + iCol),
3614
0
                            _mm_avg_epu8(inputVal0, inputVal1));
3615
0
                    }
3616
0
                    for (; iCol < nXSize; ++iCol)
3617
0
                    {
3618
0
                        uint32_t acc = 1 +
3619
0
                                       static_cast<const T * CPL_RESTRICT>(
3620
0
                                           papoSources[0])[iOffsetLine + iCol] +
3621
0
                                       static_cast<const T * CPL_RESTRICT>(
3622
0
                                           papoSources[1])[iOffsetLine + iCol];
3623
0
                        pDest[iCol] = static_cast<T>(acc / 2);
3624
0
                    }
3625
0
                }
3626
0
            }
3627
0
            else
3628
0
            {
3629
0
                libdivide::divider<uint16_t> fast_d(
3630
0
                    static_cast<uint16_t>(nSources));
3631
0
                const auto halfConstant =
3632
0
                    _mm_set1_epi16(static_cast<int16_t>(nSources / 2));
3633
0
                for (int iLine = 0; iLine < nYSize; ++iLine)
3634
0
                {
3635
0
                    T *CPL_RESTRICT pDest =
3636
0
                        static_cast<GByte *>(pData) +
3637
0
                        static_cast<GSpacing>(nLineSpace) * iLine;
3638
0
                    const size_t iOffsetLine =
3639
0
                        static_cast<size_t>(iLine) * nXSize;
3640
0
                    int iCol = 0;
3641
0
                    for (; iCol < nXSize - (VALUES_PER_REG - 1);
3642
0
                         iCol += VALUES_PER_REG)
3643
0
                    {
3644
0
                        __m128i reg0 = halfConstant;
3645
0
                        __m128i reg1 = halfConstant;
3646
0
                        for (int iSrc = 0; iSrc < nSources; ++iSrc)
3647
0
                        {
3648
0
                            const __m128i inputVal = _mm_loadu_si128(
3649
0
                                reinterpret_cast<const __m128i *>(
3650
0
                                    static_cast<const T * CPL_RESTRICT>(
3651
0
                                        papoSources[iSrc]) +
3652
0
                                    iOffsetLine + iCol));
3653
0
                            reg0 = _mm_add_epi16(
3654
0
                                reg0, _mm_unpacklo_epi8(inputVal,
3655
0
                                                        _mm_setzero_si128()));
3656
0
                            reg1 = _mm_add_epi16(
3657
0
                                reg1, _mm_unpackhi_epi8(inputVal,
3658
0
                                                        _mm_setzero_si128()));
3659
0
                        }
3660
0
                        reg0 /= fast_d;
3661
0
                        reg1 /= fast_d;
3662
0
                        _mm_storeu_si128(
3663
0
                            reinterpret_cast<__m128i *>(pDest + iCol),
3664
0
                            _mm_packus_epi16(reg0, reg1));
3665
0
                    }
3666
0
                    for (; iCol < nXSize; ++iCol)
3667
0
                    {
3668
0
                        uint32_t acc = nSources / 2;
3669
0
                        for (int iSrc = 0; iSrc < nSources; ++iSrc)
3670
0
                        {
3671
0
                            acc += static_cast<const T * CPL_RESTRICT>(
3672
0
                                papoSources[iSrc])[iOffsetLine + iCol];
3673
0
                        }
3674
0
                        pDest[iCol] = static_cast<T>(acc / nSources);
3675
0
                    }
3676
0
                }
3677
0
            }
3678
0
            return CE_None;
3679
0
        }
3680
3681
0
        if (!bHasNoData && eSrcType == GDT_Byte && eBufType == GDT_Byte &&
3682
0
            nPixelSpace == 1 &&
3683
            // We use signed int32 to accumulate
3684
0
            nSources <= std::numeric_limits<int32_t>::max() /
3685
0
                            std::numeric_limits<uint8_t>::max())
3686
0
        {
3687
0
            using T = uint8_t;
3688
0
            constexpr int VALUES_PER_REG = 16;
3689
0
            libdivide::divider<uint32_t> fast_d(nSources);
3690
0
            const auto halfConstant = _mm_set1_epi32(nSources / 2);
3691
0
            for (int iLine = 0; iLine < nYSize; ++iLine)
3692
0
            {
3693
0
                T *CPL_RESTRICT pDest =
3694
0
                    static_cast<GByte *>(pData) +
3695
0
                    static_cast<GSpacing>(nLineSpace) * iLine;
3696
0
                const size_t iOffsetLine = static_cast<size_t>(iLine) * nXSize;
3697
0
                int iCol = 0;
3698
0
                for (; iCol < nXSize - (VALUES_PER_REG - 1);
3699
0
                     iCol += VALUES_PER_REG)
3700
0
                {
3701
0
                    __m128i reg0 = halfConstant;
3702
0
                    __m128i reg1 = halfConstant;
3703
0
                    __m128i reg2 = halfConstant;
3704
0
                    __m128i reg3 = halfConstant;
3705
0
                    for (int iSrc = 0; iSrc < nSources; ++iSrc)
3706
0
                    {
3707
0
                        const __m128i inputVal =
3708
0
                            _mm_loadu_si128(reinterpret_cast<const __m128i *>(
3709
0
                                static_cast<const T * CPL_RESTRICT>(
3710
0
                                    papoSources[iSrc]) +
3711
0
                                iOffsetLine + iCol));
3712
0
                        const __m128i low =
3713
0
                            _mm_unpacklo_epi8(inputVal, _mm_setzero_si128());
3714
0
                        const __m128i high =
3715
0
                            _mm_unpackhi_epi8(inputVal, _mm_setzero_si128());
3716
0
                        reg0 = _mm_add_epi32(
3717
0
                            reg0, _mm_unpacklo_epi16(low, _mm_setzero_si128()));
3718
0
                        reg1 = _mm_add_epi32(
3719
0
                            reg1, _mm_unpackhi_epi16(low, _mm_setzero_si128()));
3720
0
                        reg2 = _mm_add_epi32(
3721
0
                            reg2,
3722
0
                            _mm_unpacklo_epi16(high, _mm_setzero_si128()));
3723
0
                        reg3 = _mm_add_epi32(
3724
0
                            reg3,
3725
0
                            _mm_unpackhi_epi16(high, _mm_setzero_si128()));
3726
0
                    }
3727
0
                    reg0 /= fast_d;
3728
0
                    reg1 /= fast_d;
3729
0
                    reg2 /= fast_d;
3730
0
                    reg3 /= fast_d;
3731
0
                    _mm_storeu_si128(
3732
0
                        reinterpret_cast<__m128i *>(pDest + iCol),
3733
0
                        _mm_packus_epi16(packus_epi32(reg0, reg1),
3734
0
                                         packus_epi32(reg2, reg3)));
3735
0
                }
3736
0
                for (; iCol < nXSize; ++iCol)
3737
0
                {
3738
0
                    uint32_t acc = nSources / 2;
3739
0
                    for (int iSrc = 0; iSrc < nSources; ++iSrc)
3740
0
                    {
3741
0
                        acc += static_cast<const T * CPL_RESTRICT>(
3742
0
                            papoSources[iSrc])[iOffsetLine + iCol];
3743
0
                    }
3744
0
                    pDest[iCol] = static_cast<T>(acc / nSources);
3745
0
                }
3746
0
            }
3747
0
            return CE_None;
3748
0
        }
3749
3750
0
        if (!bHasNoData && eSrcType == GDT_UInt16 && eBufType == GDT_UInt16 &&
3751
0
            nPixelSpace == 2 &&
3752
0
            nSources <= std::numeric_limits<int32_t>::max() /
3753
0
                            std::numeric_limits<uint16_t>::max())
3754
0
        {
3755
0
            libdivide::divider<uint32_t> fast_d(nSources);
3756
0
            using T = uint16_t;
3757
0
            const auto halfConstant = _mm_set1_epi32(nSources / 2);
3758
0
            constexpr int VALUES_PER_REG = 8;
3759
0
            for (int iLine = 0; iLine < nYSize; ++iLine)
3760
0
            {
3761
0
                T *CPL_RESTRICT pDest = reinterpret_cast<T *>(
3762
0
                    static_cast<GByte *>(pData) +
3763
0
                    static_cast<GSpacing>(nLineSpace) * iLine);
3764
0
                const size_t iOffsetLine = static_cast<size_t>(iLine) * nXSize;
3765
0
                int iCol = 0;
3766
0
                for (; iCol < nXSize - (VALUES_PER_REG - 1);
3767
0
                     iCol += VALUES_PER_REG)
3768
0
                {
3769
0
                    __m128i reg0 = halfConstant;
3770
0
                    __m128i reg1 = halfConstant;
3771
0
                    for (int iSrc = 0; iSrc < nSources; ++iSrc)
3772
0
                    {
3773
0
                        const __m128i inputVal =
3774
0
                            _mm_loadu_si128(reinterpret_cast<const __m128i *>(
3775
0
                                static_cast<const T * CPL_RESTRICT>(
3776
0
                                    papoSources[iSrc]) +
3777
0
                                iOffsetLine + iCol));
3778
0
                        reg0 = _mm_add_epi32(
3779
0
                            reg0,
3780
0
                            _mm_unpacklo_epi16(inputVal, _mm_setzero_si128()));
3781
0
                        reg1 = _mm_add_epi32(
3782
0
                            reg1,
3783
0
                            _mm_unpackhi_epi16(inputVal, _mm_setzero_si128()));
3784
0
                    }
3785
0
                    reg0 /= fast_d;
3786
0
                    reg1 /= fast_d;
3787
0
                    _mm_storeu_si128(reinterpret_cast<__m128i *>(pDest + iCol),
3788
0
                                     packus_epi32(reg0, reg1));
3789
0
                }
3790
0
                for (; iCol < nXSize; ++iCol)
3791
0
                {
3792
0
                    uint32_t acc = nSources / 2;
3793
0
                    for (int iSrc = 0; iSrc < nSources; ++iSrc)
3794
0
                    {
3795
0
                        acc += static_cast<const T * CPL_RESTRICT>(
3796
0
                            papoSources[iSrc])[iOffsetLine + iCol];
3797
0
                    }
3798
0
                    pDest[iCol] = static_cast<T>(acc / nSources);
3799
0
                }
3800
0
            }
3801
0
            return CE_None;
3802
0
        }
3803
3804
0
        if (!bHasNoData && eSrcType == GDT_Int16 && eBufType == GDT_Int16 &&
3805
0
            nPixelSpace == 2 &&
3806
0
            nSources <= std::numeric_limits<int32_t>::max() /
3807
0
                            std::numeric_limits<uint16_t>::max())
3808
0
        {
3809
0
            libdivide::divider<uint32_t> fast_d(nSources);
3810
0
            using T = int16_t;
3811
0
            const auto halfConstant = _mm_set1_epi32(nSources / 2);
3812
0
            const auto shift = _mm_set1_epi16(std::numeric_limits<T>::min());
3813
0
            constexpr int VALUES_PER_REG = 8;
3814
0
            for (int iLine = 0; iLine < nYSize; ++iLine)
3815
0
            {
3816
0
                T *CPL_RESTRICT pDest = reinterpret_cast<T *>(
3817
0
                    static_cast<GByte *>(pData) +
3818
0
                    static_cast<GSpacing>(nLineSpace) * iLine);
3819
0
                const size_t iOffsetLine = static_cast<size_t>(iLine) * nXSize;
3820
0
                int iCol = 0;
3821
0
                for (; iCol < nXSize - (VALUES_PER_REG - 1);
3822
0
                     iCol += VALUES_PER_REG)
3823
0
                {
3824
0
                    __m128i reg0 = halfConstant;
3825
0
                    __m128i reg1 = halfConstant;
3826
0
                    for (int iSrc = 0; iSrc < nSources; ++iSrc)
3827
0
                    {
3828
                        // Shift input values by 32768 to get unsigned values
3829
0
                        const __m128i inputVal = _mm_add_epi16(
3830
0
                            _mm_loadu_si128(reinterpret_cast<const __m128i *>(
3831
0
                                static_cast<const T * CPL_RESTRICT>(
3832
0
                                    papoSources[iSrc]) +
3833
0
                                iOffsetLine + iCol)),
3834
0
                            shift);
3835
0
                        reg0 = _mm_add_epi32(
3836
0
                            reg0,
3837
0
                            _mm_unpacklo_epi16(inputVal, _mm_setzero_si128()));
3838
0
                        reg1 = _mm_add_epi32(
3839
0
                            reg1,
3840
0
                            _mm_unpackhi_epi16(inputVal, _mm_setzero_si128()));
3841
0
                    }
3842
0
                    reg0 /= fast_d;
3843
0
                    reg1 /= fast_d;
3844
0
                    _mm_storeu_si128(
3845
0
                        reinterpret_cast<__m128i *>(pDest + iCol),
3846
0
                        _mm_add_epi16(packus_epi32(reg0, reg1), shift));
3847
0
                }
3848
0
                for (; iCol < nXSize; ++iCol)
3849
0
                {
3850
0
                    int32_t acc = (-std::numeric_limits<T>::min()) * nSources +
3851
0
                                  nSources / 2;
3852
0
                    for (int iSrc = 0; iSrc < nSources; ++iSrc)
3853
0
                    {
3854
0
                        acc += static_cast<const T * CPL_RESTRICT>(
3855
0
                            papoSources[iSrc])[iOffsetLine + iCol];
3856
0
                    }
3857
0
                    pDest[iCol] = static_cast<T>(acc / nSources +
3858
0
                                                 std::numeric_limits<T>::min());
3859
0
                }
3860
0
            }
3861
0
            return CE_None;
3862
0
        }
3863
0
    }
3864
0
#endif  // defined(USE_SSE2) && !defined(USE_NEON_OPTIMIZATIONS)
3865
3866
0
#if defined(USE_SSE2)
3867
    if constexpr (std::is_same_v<Kernel, MeanKernel>)
3868
0
    {
3869
0
        if (!bHasNoData && eSrcType == GDT_Float32 && eBufType == GDT_Float32 &&
3870
0
            nPixelSpace == 4 && nSources > 0)
3871
0
        {
3872
0
            OptimizedMeanFloatSSE2<float, SSEWrapperFloat>(
3873
0
                papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
3874
0
            return CE_None;
3875
0
        }
3876
3877
0
        if (!bHasNoData && eSrcType == GDT_Float64 && eBufType == GDT_Float64 &&
3878
0
            nPixelSpace == 8 && nSources > 0)
3879
0
        {
3880
0
            OptimizedMeanFloatSSE2<double, SSEWrapperDouble>(
3881
0
                papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
3882
0
            return CE_None;
3883
0
        }
3884
0
    }
3885
0
#endif  // USE_SSE2
3886
3887
    /* ---- Set pixels ---- */
3888
0
    size_t ii = 0;
3889
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
3890
0
    {
3891
0
        for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
3892
0
        {
3893
0
            oKernel.Reset();
3894
0
            bool bWriteNoData = false;
3895
3896
0
            for (int iSrc = 0; iSrc < nSources; ++iSrc)
3897
0
            {
3898
0
                const double dfVal = GetSrcVal(papoSources[iSrc], eSrcType, ii);
3899
3900
0
                if (bHasNoData && IsNoData(dfVal, dfNoData))
3901
0
                {
3902
0
                    if (bPropagateNoData)
3903
0
                    {
3904
0
                        bWriteNoData = true;
3905
0
                        break;
3906
0
                    }
3907
0
                }
3908
0
                else
3909
0
                {
3910
0
                    oKernel.ProcessPixel(dfVal);
3911
0
                }
3912
0
            }
3913
3914
0
            double dfPixVal{dfNoData};
3915
0
            if (!bWriteNoData && oKernel.HasValue())
3916
0
            {
3917
0
                dfPixVal = oKernel.GetValue();
3918
0
            }
3919
3920
0
            GDALCopyWords(&dfPixVal, GDT_Float64, 0,
3921
0
                          static_cast<GByte *>(pData) +
3922
0
                              static_cast<GSpacing>(nLineSpace) * iLine +
3923
0
                              iCol * nPixelSpace,
3924
0
                          eBufType, nPixelSpace, 1);
3925
0
        }
3926
0
    }
3927
3928
    /* ---- Return success ---- */
3929
0
    return CE_None;
3930
0
}  // BasicPixelFunc
Unexecuted instantiation: pixelfunctions.cpp:CPLErr BasicPixelFunc<MeanKernel>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)
Unexecuted instantiation: pixelfunctions.cpp:CPLErr BasicPixelFunc<GeoMeanKernel>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)
Unexecuted instantiation: pixelfunctions.cpp:CPLErr BasicPixelFunc<HarmonicMeanKernel>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)
Unexecuted instantiation: pixelfunctions.cpp:CPLErr BasicPixelFunc<MedianKernel>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)
Unexecuted instantiation: pixelfunctions.cpp:CPLErr BasicPixelFunc<ModeKernel>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)
3931
3932
/************************************************************************/
3933
/*                     GDALRegisterDefaultPixelFunc()                   */
3934
/************************************************************************/
3935
3936
/**
3937
 * This adds a default set of pixel functions to the global list of
3938
 * available pixel functions for derived bands:
3939
 *
3940
 * - "real": extract real part from a single raster band (just a copy if the
3941
 *           input is non-complex)
3942
 * - "imag": extract imaginary part from a single raster band (0 for
3943
 *           non-complex)
3944
 * - "complex": make a complex band merging two bands used as real and
3945
 *              imag values
3946
 * - "polar": make a complex band using input bands for amplitude and
3947
 *            phase values (b1 * exp( j * b2 ))
3948
 * - "mod": extract module from a single raster band (real or complex)
3949
 * - "phase": extract phase from a single raster band [-PI,PI] (0 or PI for
3950
              non-complex)
3951
 * - "conj": computes the complex conjugate of a single raster band (just a
3952
 *           copy if the input is non-complex)
3953
 * - "sum": sum 2 or more raster bands
3954
 * - "diff": computes the difference between 2 raster bands (b1 - b2)
3955
 * - "mul": multiply 2 or more raster bands
3956
 * - "div": divide one raster band by another (b1 / b2).
3957
 * - "min": minimum value of 2 or more raster bands
3958
 * - "max": maximum value of 2 or more raster bands
3959
 * - "norm_diff": computes the normalized difference between two raster bands:
3960
 *                ``(b1 - b2)/(b1 + b2)``.
3961
 * - "cmul": multiply the first band for the complex conjugate of the second
3962
 * - "inv": inverse (1./x).
3963
 * - "intensity": computes the intensity Re(x*conj(x)) of a single raster band
3964
 *                (real or complex)
3965
 * - "sqrt": perform the square root of a single raster band (real only)
3966
 * - "log10": compute the logarithm (base 10) of the abs of a single raster
3967
 *            band (real or complex): log10( abs( x ) )
3968
 * - "dB": perform conversion to dB of the abs of a single raster
3969
 *         band (real or complex): 20. * log10( abs( x ) ).
3970
 *         Note: the optional fact parameter can be set to 10. to get the
3971
 *         alternative formula: 10. * log10( abs( x ) )
3972
 * - "exp": computes the exponential of each element in the input band ``x``
3973
 *          (of real values): ``e ^ x``.
3974
 *          The function also accepts two optional parameters: ``base`` and
3975
 ``fact``
3976
 *          that allow to compute the generalized formula: ``base ^ ( fact *
3977
 x)``.
3978
 *          Note: this function is the recommended one to perform conversion
3979
 *          form logarithmic scale (dB): `` 10. ^ (x / 20.)``, in this case
3980
 *          ``base = 10.`` and ``fact = 1./20``
3981
 * - "dB2amp": perform scale conversion from logarithmic to linear
3982
 *             (amplitude) (i.e. 10 ^ ( x / 20 ) ) of a single raster
3983
 *             band (real only).
3984
 *             Deprecated in GDAL v3.5. Please use the ``exp`` pixel function
3985
 with
3986
 *             ``base = 10.`` and ``fact = 0.05`` i.e. ``1./20``
3987
 * - "dB2pow": perform scale conversion from logarithmic to linear
3988
 *             (power) (i.e. 10 ^ ( x / 10 ) ) of a single raster
3989
 *             band (real only)
3990
 *             Deprecated in GDAL v3.5. Please use the ``exp`` pixel function
3991
 with
3992
 *             ``base = 10.`` and ``fact = 0.1`` i.e. ``1./10``
3993
 * - "pow": raise a single raster band to a constant power
3994
 * - "interpolate_linear": interpolate values between two raster bands
3995
 *                         using linear interpolation
3996
 * - "interpolate_exp": interpolate values between two raster bands using
3997
 *                      exponential interpolation
3998
 * - "scale": Apply the RasterBand metadata values of "offset" and "scale"
3999
 * - "reclassify": Reclassify values matching ranges in a table
4000
 * - "nan": Convert incoming NoData values to IEEE 754 nan
4001
 *
4002
 * @see GDALAddDerivedBandPixelFunc
4003
 *
4004
 * @return CE_None
4005
 */
4006
CPLErr GDALRegisterDefaultPixelFunc()
4007
24
{
4008
24
    GDALAddDerivedBandPixelFunc("real", RealPixelFunc);
4009
24
    GDALAddDerivedBandPixelFunc("imag", ImagPixelFunc);
4010
24
    GDALAddDerivedBandPixelFunc("complex", ComplexPixelFunc);
4011
24
    GDALAddDerivedBandPixelFuncWithArgs("polar", PolarPixelFunc,
4012
24
                                        pszPolarPixelFuncMetadata);
4013
24
    GDALAddDerivedBandPixelFunc("mod", ModulePixelFunc);
4014
24
    GDALAddDerivedBandPixelFunc("phase", PhasePixelFunc);
4015
24
    GDALAddDerivedBandPixelFunc("conj", ConjPixelFunc);
4016
24
    GDALAddDerivedBandPixelFuncWithArgs("sum", SumPixelFunc,
4017
24
                                        pszSumPixelFuncMetadata);
4018
24
    GDALAddDerivedBandPixelFuncWithArgs("diff", DiffPixelFunc,
4019
24
                                        pszDiffPixelFuncMetadata);
4020
24
    GDALAddDerivedBandPixelFuncWithArgs("mul", MulPixelFunc,
4021
24
                                        pszMulPixelFuncMetadata);
4022
24
    GDALAddDerivedBandPixelFuncWithArgs("div", DivPixelFunc,
4023
24
                                        pszDivPixelFuncMetadata);
4024
24
    GDALAddDerivedBandPixelFunc("cmul", CMulPixelFunc);
4025
24
    GDALAddDerivedBandPixelFuncWithArgs("inv", InvPixelFunc,
4026
24
                                        pszInvPixelFuncMetadata);
4027
24
    GDALAddDerivedBandPixelFunc("intensity", IntensityPixelFunc);
4028
24
    GDALAddDerivedBandPixelFuncWithArgs("sqrt", SqrtPixelFunc,
4029
24
                                        pszSqrtPixelFuncMetadata);
4030
24
    GDALAddDerivedBandPixelFuncWithArgs("log10", Log10PixelFunc,
4031
24
                                        pszLog10PixelFuncMetadata);
4032
24
    GDALAddDerivedBandPixelFuncWithArgs("dB", DBPixelFunc,
4033
24
                                        pszDBPixelFuncMetadata);
4034
24
    GDALAddDerivedBandPixelFuncWithArgs("exp", ExpPixelFunc,
4035
24
                                        pszExpPixelFuncMetadata);
4036
24
    GDALAddDerivedBandPixelFunc("dB2amp",
4037
24
                                dB2AmpPixelFunc);  // deprecated in v3.5
4038
24
    GDALAddDerivedBandPixelFunc("dB2pow",
4039
24
                                dB2PowPixelFunc);  // deprecated in v3.5
4040
24
    GDALAddDerivedBandPixelFuncWithArgs("pow", PowPixelFunc,
4041
24
                                        pszPowPixelFuncMetadata);
4042
24
    GDALAddDerivedBandPixelFuncWithArgs("interpolate_linear",
4043
24
                                        InterpolatePixelFunc<InterpolateLinear>,
4044
24
                                        pszInterpolatePixelFuncMetadata);
4045
24
    GDALAddDerivedBandPixelFuncWithArgs(
4046
24
        "interpolate_exp", InterpolatePixelFunc<InterpolateExponential>,
4047
24
        pszInterpolatePixelFuncMetadata);
4048
24
    GDALAddDerivedBandPixelFuncWithArgs("replace_nodata",
4049
24
                                        ReplaceNoDataPixelFunc,
4050
24
                                        pszReplaceNoDataPixelFuncMetadata);
4051
24
    GDALAddDerivedBandPixelFuncWithArgs("scale", ScalePixelFunc,
4052
24
                                        pszScalePixelFuncMetadata);
4053
24
    GDALAddDerivedBandPixelFuncWithArgs("norm_diff", NormDiffPixelFunc,
4054
24
                                        pszNormDiffPixelFuncMetadata);
4055
24
    GDALAddDerivedBandPixelFuncWithArgs("min", MinPixelFunc<ReturnValue>,
4056
24
                                        pszMinMaxFuncMetadataNodata);
4057
24
    GDALAddDerivedBandPixelFuncWithArgs("argmin", MinPixelFunc<ReturnIndex>,
4058
24
                                        pszArgMinMaxFuncMetadataNodata);
4059
24
    GDALAddDerivedBandPixelFuncWithArgs("max", MaxPixelFunc<ReturnValue>,
4060
24
                                        pszMinMaxFuncMetadataNodata);
4061
24
    GDALAddDerivedBandPixelFuncWithArgs("argmax", MaxPixelFunc<ReturnIndex>,
4062
24
                                        pszArgMinMaxFuncMetadataNodata);
4063
24
    GDALAddDerivedBandPixelFuncWithArgs("expression", ExprPixelFunc,
4064
24
                                        pszExprPixelFuncMetadata);
4065
24
    GDALAddDerivedBandPixelFuncWithArgs("reclassify", ReclassifyPixelFunc,
4066
24
                                        pszReclassifyPixelFuncMetadata);
4067
24
    GDALAddDerivedBandPixelFuncWithArgs("mean", BasicPixelFunc<MeanKernel>,
4068
24
                                        pszBasicPixelFuncMetadata);
4069
24
    GDALAddDerivedBandPixelFuncWithArgs("geometric_mean",
4070
24
                                        BasicPixelFunc<GeoMeanKernel>,
4071
24
                                        pszBasicPixelFuncMetadata);
4072
24
    GDALAddDerivedBandPixelFuncWithArgs("harmonic_mean",
4073
24
                                        BasicPixelFunc<HarmonicMeanKernel>,
4074
24
                                        pszBasicPixelFuncMetadata);
4075
24
    GDALAddDerivedBandPixelFuncWithArgs("median", BasicPixelFunc<MedianKernel>,
4076
24
                                        pszBasicPixelFuncMetadata);
4077
24
    GDALAddDerivedBandPixelFuncWithArgs("mode", BasicPixelFunc<ModeKernel>,
4078
24
                                        pszBasicPixelFuncMetadata);
4079
24
    return CE_None;
4080
24
}