Coverage Report

Created: 2025-06-22 06:59

/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 pszMinMaxFuncMetadataNodata[] =
2350
    "<PixelFunctionArgumentsList>"
2351
    "   <Argument name='k' description='Optional constant term' type='double' "
2352
    "default='nan' />"
2353
    "   <Argument type='builtin' value='NoData' optional='true' />"
2354
    "   <Argument name='propagateNoData' description='Whether the output value "
2355
    "should be NoData as as soon as one source is NoData' type='boolean' "
2356
    "default='false' />"
2357
    "</PixelFunctionArgumentsList>";
2358
2359
template <class Comparator>
2360
static CPLErr MinOrMaxPixelFunc(double dfK, void **papoSources, int nSources,
2361
                                void *pData, int nXSize, int nYSize,
2362
                                GDALDataType eSrcType, GDALDataType eBufType,
2363
                                int nPixelSpace, int nLineSpace,
2364
                                CSLConstList papszArgs)
2365
0
{
2366
    /* ---- Init ---- */
2367
0
    if (GDALDataTypeIsComplex(eSrcType))
2368
0
    {
2369
0
        CPLError(CE_Failure, CPLE_AppDefined,
2370
0
                 "Complex data type not supported for min/max().");
2371
0
        return CE_Failure;
2372
0
    }
2373
2374
0
    double dfNoData = std::numeric_limits<double>::quiet_NaN();
2375
0
    if (FetchDoubleArg(papszArgs, "NoData", &dfNoData, &dfNoData) != CE_None)
2376
0
        return CE_Failure;
2377
0
    const bool bPropagateNoData = CPLTestBool(
2378
0
        CSLFetchNameValueDef(papszArgs, "propagateNoData", "false"));
2379
2380
    /* ---- Set pixels ---- */
2381
0
    size_t ii = 0;
2382
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
2383
0
    {
2384
0
        for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
2385
0
        {
2386
0
            double dfRes = std::numeric_limits<double>::quiet_NaN();
2387
2388
0
            for (int iSrc = 0; iSrc < nSources; ++iSrc)
2389
0
            {
2390
0
                const double dfVal = GetSrcVal(papoSources[iSrc], eSrcType, ii);
2391
2392
0
                if (std::isnan(dfVal) || dfVal == dfNoData)
2393
0
                {
2394
0
                    if (bPropagateNoData)
2395
0
                    {
2396
0
                        dfRes = dfNoData;
2397
0
                        break;
2398
0
                    }
2399
0
                }
2400
0
                else if (Comparator::compare(dfVal, dfRes))
2401
0
                {
2402
0
                    dfRes = dfVal;
2403
0
                }
2404
0
            }
2405
2406
0
            if (std::isnan(dfRes))
2407
0
            {
2408
0
                if (!bPropagateNoData)
2409
0
                    dfRes = dfNoData;
2410
0
            }
2411
0
            else if (!std::isnan(dfK) && Comparator::compare(dfK, dfRes))
2412
0
            {
2413
0
                dfRes = dfK;
2414
0
            }
2415
2416
0
            GDALCopyWords(&dfRes, GDT_Float64, 0,
2417
0
                          static_cast<GByte *>(pData) +
2418
0
                              static_cast<GSpacing>(nLineSpace) * iLine +
2419
0
                              iCol * nPixelSpace,
2420
0
                          eBufType, nPixelSpace, 1);
2421
0
        }
2422
0
    }
2423
2424
    /* ---- Return success ---- */
2425
0
    return CE_None;
2426
0
} /* MinOrMaxPixelFunc */
Unexecuted instantiation: pixelfunctions.cpp:CPLErr MinOrMaxPixelFunc<MinPixelFunc(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)::Comparator>(double, void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)
Unexecuted instantiation: pixelfunctions.cpp:CPLErr MinOrMaxPixelFunc<MaxPixelFunc(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)::Comparator>(double, void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)
2427
2428
#ifdef USE_SSE2
2429
2430
template <class T, class SSEWrapper>
2431
static void OptimizedMinOrMaxSSE2(const void *const *papoSources, int nSources,
2432
                                  void *pData, int nXSize, int nYSize,
2433
                                  int nLineSpace)
2434
0
{
2435
0
    assert(nSources >= 1);
2436
0
    constexpr int VALUES_PER_REG =
2437
0
        static_cast<int>(sizeof(typename SSEWrapper::Vec) / sizeof(T));
2438
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
2439
0
    {
2440
0
        T *CPL_RESTRICT pDest =
2441
0
            reinterpret_cast<T *>(static_cast<GByte *>(pData) +
2442
0
                                  static_cast<GSpacing>(nLineSpace) * iLine);
2443
0
        const size_t iOffsetLine = static_cast<size_t>(iLine) * nXSize;
2444
0
        int iCol = 0;
2445
0
        for (; iCol < nXSize - (2 * VALUES_PER_REG - 1);
2446
0
             iCol += 2 * VALUES_PER_REG)
2447
0
        {
2448
0
            auto reg0 = SSEWrapper::LoadU(
2449
0
                static_cast<const T * CPL_RESTRICT>(papoSources[0]) +
2450
0
                iOffsetLine + iCol);
2451
0
            auto reg1 = SSEWrapper::LoadU(
2452
0
                static_cast<const T * CPL_RESTRICT>(papoSources[0]) +
2453
0
                iOffsetLine + iCol + VALUES_PER_REG);
2454
0
            for (int iSrc = 1; iSrc < nSources; ++iSrc)
2455
0
            {
2456
0
                reg0 = SSEWrapper::MinOrMax(
2457
0
                    reg0, SSEWrapper::LoadU(static_cast<const T * CPL_RESTRICT>(
2458
0
                                                papoSources[iSrc]) +
2459
0
                                            iOffsetLine + iCol));
2460
0
                reg1 = SSEWrapper::MinOrMax(
2461
0
                    reg1,
2462
0
                    SSEWrapper::LoadU(
2463
0
                        static_cast<const T * CPL_RESTRICT>(papoSources[iSrc]) +
2464
0
                        iOffsetLine + iCol + VALUES_PER_REG));
2465
0
            }
2466
0
            SSEWrapper::StoreU(pDest + iCol, reg0);
2467
0
            SSEWrapper::StoreU(pDest + iCol + VALUES_PER_REG, reg1);
2468
0
        }
2469
0
        for (; iCol < nXSize; ++iCol)
2470
0
        {
2471
0
            T v = static_cast<const T * CPL_RESTRICT>(
2472
0
                papoSources[0])[iOffsetLine + iCol];
2473
0
            for (int iSrc = 1; iSrc < nSources; ++iSrc)
2474
0
            {
2475
0
                v = SSEWrapper::MinOrMax(
2476
0
                    v, static_cast<const T * CPL_RESTRICT>(
2477
0
                           papoSources[iSrc])[iOffsetLine + iCol]);
2478
0
            }
2479
0
            pDest[iCol] = v;
2480
0
        }
2481
0
    }
2482
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)
2483
2484
// clang-format off
2485
namespace
2486
{
2487
struct SSEWrapperMinByte
2488
{
2489
    using T = uint8_t;
2490
    typedef __m128i Vec;
2491
2492
0
    static inline Vec LoadU(const T *x) { return _mm_loadu_si128(reinterpret_cast<const Vec*>(x)); }
2493
0
    static inline void StoreU(T *x, Vec y) { _mm_storeu_si128(reinterpret_cast<Vec*>(x), y); }
2494
0
    static inline Vec MinOrMax(Vec x, Vec y) { return _mm_min_epu8(x, y); }
2495
0
    static inline T MinOrMax(T x, T y) { return std::min(x, y); }
2496
};
2497
2498
struct SSEWrapperMaxByte
2499
{
2500
    using T = uint8_t;
2501
    typedef __m128i Vec;
2502
2503
0
    static inline Vec LoadU(const T *x) { return _mm_loadu_si128(reinterpret_cast<const Vec*>(x)); }
2504
0
    static inline void StoreU(T *x, Vec y) { _mm_storeu_si128(reinterpret_cast<Vec*>(x), y); }
2505
0
    static inline Vec MinOrMax(Vec x, Vec y) { return _mm_max_epu8(x, y); }
2506
0
    static inline T MinOrMax(T x, T y) { return std::max(x, y); }
2507
};
2508
2509
struct SSEWrapperMinUInt16
2510
{
2511
    using T = uint16_t;
2512
    typedef __m128i Vec;
2513
2514
0
    static inline Vec LoadU(const T *x) { return _mm_loadu_si128(reinterpret_cast<const Vec*>(x)); }
2515
0
    static inline void StoreU(T *x, Vec y) { _mm_storeu_si128(reinterpret_cast<Vec*>(x), y); }
2516
#if defined(__SSE4_1__) || defined(USE_NEON_OPTIMIZATIONS)
2517
    static inline Vec MinOrMax(Vec x, Vec y) { return _mm_min_epu16(x, y); }
2518
#else
2519
0
    static inline Vec MinOrMax(Vec x, Vec y) { return
2520
0
        _mm_add_epi16(
2521
0
           _mm_min_epi16(
2522
0
             _mm_add_epi16(x, _mm_set1_epi16(-32768)),
2523
0
             _mm_add_epi16(y, _mm_set1_epi16(-32768))),
2524
0
           _mm_set1_epi16(-32768)); }
2525
#endif
2526
0
    static inline T MinOrMax(T x, T y) { return std::min(x, y); }
2527
};
2528
2529
struct SSEWrapperMaxUInt16
2530
{
2531
    using T = uint16_t;
2532
    typedef __m128i Vec;
2533
2534
0
    static inline Vec LoadU(const T *x) { return _mm_loadu_si128(reinterpret_cast<const Vec*>(x)); }
2535
0
    static inline void StoreU(T *x, Vec y) { _mm_storeu_si128(reinterpret_cast<Vec*>(x), y); }
2536
#if defined(__SSE4_1__) || defined(USE_NEON_OPTIMIZATIONS)
2537
    static inline Vec MinOrMax(Vec x, Vec y) { return _mm_max_epu16(x, y); }
2538
#else
2539
0
    static inline Vec MinOrMax(Vec x, Vec y) { return
2540
0
        _mm_add_epi16(
2541
0
           _mm_max_epi16(
2542
0
             _mm_add_epi16(x, _mm_set1_epi16(-32768)),
2543
0
             _mm_add_epi16(y, _mm_set1_epi16(-32768))),
2544
0
           _mm_set1_epi16(-32768)); }
2545
#endif
2546
0
    static inline T MinOrMax(T x, T y) { return std::max(x, y); }
2547
};
2548
2549
struct SSEWrapperMinInt16
2550
{
2551
    using T = int16_t;
2552
    typedef __m128i Vec;
2553
2554
0
    static inline Vec LoadU(const T *x) { return _mm_loadu_si128(reinterpret_cast<const Vec*>(x)); }
2555
0
    static inline void StoreU(T *x, Vec y) { _mm_storeu_si128(reinterpret_cast<Vec*>(x), y); }
2556
0
    static inline Vec MinOrMax(Vec x, Vec y) { return _mm_min_epi16(x, y); }
2557
0
    static inline T MinOrMax(T x, T y) { return std::min(x, y); }
2558
};
2559
2560
struct SSEWrapperMaxInt16
2561
{
2562
    using T = int16_t;
2563
    typedef __m128i Vec;
2564
2565
0
    static inline Vec LoadU(const T *x) { return _mm_loadu_si128(reinterpret_cast<const Vec*>(x)); }
2566
0
    static inline void StoreU(T *x, Vec y) { _mm_storeu_si128(reinterpret_cast<Vec*>(x), y); }
2567
0
    static inline Vec MinOrMax(Vec x, Vec y) { return _mm_max_epi16(x, y); }
2568
0
    static inline T MinOrMax(T x, T y) { return std::max(x, y); }
2569
};
2570
2571
struct SSEWrapperMinFloat
2572
{
2573
    using T = float;
2574
    typedef __m128 Vec;
2575
2576
0
    static inline Vec LoadU(const T *x) { return _mm_loadu_ps(x); }
2577
0
    static inline void StoreU(T *x, Vec y) { _mm_storeu_ps(x, y); }
2578
0
    static inline Vec MinOrMax(Vec x, Vec y) { return _mm_min_ps(x, y); }
2579
0
    static inline T MinOrMax(T x, T y) { return std::min(x, y); }
2580
};
2581
2582
struct SSEWrapperMaxFloat
2583
{
2584
    using T = float;
2585
    typedef __m128 Vec;
2586
2587
0
    static inline Vec LoadU(const T *x) { return _mm_loadu_ps(x); }
2588
0
    static inline void StoreU(T *x, Vec y) { _mm_storeu_ps(x, y); }
2589
0
    static inline Vec MinOrMax(Vec x, Vec y) { return _mm_max_ps(x, y); }
2590
0
    static inline T MinOrMax(T x, T y) { return std::max(x, y); }
2591
};
2592
2593
struct SSEWrapperMinDouble
2594
{
2595
    using T = double;
2596
    typedef __m128d Vec;
2597
2598
0
    static inline Vec LoadU(const T *x) { return _mm_loadu_pd(x); }
2599
0
    static inline void StoreU(T *x, Vec y) { _mm_storeu_pd(x, y); }
2600
0
    static inline Vec MinOrMax(Vec x, Vec y) { return _mm_min_pd(x, y); }
2601
0
    static inline T MinOrMax(T x, T y) { return std::min(x, y); }
2602
};
2603
2604
struct SSEWrapperMaxDouble
2605
{
2606
    using T = double;
2607
    typedef __m128d Vec;
2608
2609
0
    static inline Vec LoadU(const T *x) { return _mm_loadu_pd(x); }
2610
0
    static inline void StoreU(T *x, Vec y) { _mm_storeu_pd(x, y); }
2611
0
    static inline Vec MinOrMax(Vec x, Vec y) { return _mm_max_pd(x, y); }
2612
0
    static inline T MinOrMax(T x, T y) { return std::max(x, y); }
2613
};
2614
2615
}  // namespace
2616
2617
// clang-format on
2618
2619
#endif  // USE_SSE2
2620
2621
static CPLErr MinPixelFunc(void **papoSources, int nSources, void *pData,
2622
                           int nXSize, int nYSize, GDALDataType eSrcType,
2623
                           GDALDataType eBufType, int nPixelSpace,
2624
                           int nLineSpace, CSLConstList papszArgs)
2625
0
{
2626
0
    struct Comparator
2627
0
    {
2628
0
        static bool compare(double x, double resVal)
2629
0
        {
2630
            // Written this way to deal with resVal being NaN
2631
0
            return !(x >= resVal);
2632
0
        }
2633
0
    };
2634
2635
0
    double dfK = std::numeric_limits<double>::quiet_NaN();
2636
0
    if (FetchDoubleArg(papszArgs, "k", &dfK, &dfK) != CE_None)
2637
0
        return CE_Failure;
2638
2639
0
#ifdef USE_SSE2
2640
0
    const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
2641
0
    if (std::isnan(dfK) && nSources > 0 && !bHasNoData &&
2642
0
        eSrcType == eBufType &&
2643
0
        nPixelSpace == GDALGetDataTypeSizeBytes(eSrcType))
2644
0
    {
2645
0
        if (eSrcType == GDT_Byte)
2646
0
        {
2647
0
            OptimizedMinOrMaxSSE2<uint8_t, SSEWrapperMinByte>(
2648
0
                papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
2649
0
            return CE_None;
2650
0
        }
2651
0
        else if (eSrcType == GDT_UInt16)
2652
0
        {
2653
0
            OptimizedMinOrMaxSSE2<uint16_t, SSEWrapperMinUInt16>(
2654
0
                papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
2655
0
            return CE_None;
2656
0
        }
2657
0
        else if (eSrcType == GDT_Int16)
2658
0
        {
2659
0
            OptimizedMinOrMaxSSE2<int16_t, SSEWrapperMinInt16>(
2660
0
                papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
2661
0
            return CE_None;
2662
0
        }
2663
0
        else if (eSrcType == GDT_Float32)
2664
0
        {
2665
0
            OptimizedMinOrMaxSSE2<float, SSEWrapperMinFloat>(
2666
0
                papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
2667
0
            return CE_None;
2668
0
        }
2669
0
        else if (eSrcType == GDT_Float64)
2670
0
        {
2671
0
            OptimizedMinOrMaxSSE2<double, SSEWrapperMinDouble>(
2672
0
                papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
2673
0
            return CE_None;
2674
0
        }
2675
0
    }
2676
0
#endif
2677
2678
0
    return MinOrMaxPixelFunc<Comparator>(dfK, papoSources, nSources, pData,
2679
0
                                         nXSize, nYSize, eSrcType, eBufType,
2680
0
                                         nPixelSpace, nLineSpace, papszArgs);
2681
0
}
2682
2683
static CPLErr MaxPixelFunc(void **papoSources, int nSources, void *pData,
2684
                           int nXSize, int nYSize, GDALDataType eSrcType,
2685
                           GDALDataType eBufType, int nPixelSpace,
2686
                           int nLineSpace, CSLConstList papszArgs)
2687
0
{
2688
0
    struct Comparator
2689
0
    {
2690
0
        static bool compare(double x, double resVal)
2691
0
        {
2692
            // Written this way to deal with resVal being NaN
2693
0
            return !(x <= resVal);
2694
0
        }
2695
0
    };
2696
2697
0
    double dfK = std::numeric_limits<double>::quiet_NaN();
2698
0
    if (FetchDoubleArg(papszArgs, "k", &dfK, &dfK) != CE_None)
2699
0
        return CE_Failure;
2700
2701
0
#ifdef USE_SSE2
2702
0
    const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
2703
0
    if (std::isnan(dfK) && nSources > 0 && !bHasNoData &&
2704
0
        eSrcType == eBufType &&
2705
0
        nPixelSpace == GDALGetDataTypeSizeBytes(eSrcType))
2706
0
    {
2707
0
        if (eSrcType == GDT_Byte)
2708
0
        {
2709
0
            OptimizedMinOrMaxSSE2<uint8_t, SSEWrapperMaxByte>(
2710
0
                papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
2711
0
            return CE_None;
2712
0
        }
2713
0
        else if (eSrcType == GDT_UInt16)
2714
0
        {
2715
0
            OptimizedMinOrMaxSSE2<uint16_t, SSEWrapperMaxUInt16>(
2716
0
                papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
2717
0
            return CE_None;
2718
0
        }
2719
0
        else if (eSrcType == GDT_Int16)
2720
0
        {
2721
0
            OptimizedMinOrMaxSSE2<int16_t, SSEWrapperMaxInt16>(
2722
0
                papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
2723
0
            return CE_None;
2724
0
        }
2725
0
        else if (eSrcType == GDT_Float32)
2726
0
        {
2727
0
            OptimizedMinOrMaxSSE2<float, SSEWrapperMaxFloat>(
2728
0
                papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
2729
0
            return CE_None;
2730
0
        }
2731
0
        else if (eSrcType == GDT_Float64)
2732
0
        {
2733
0
            OptimizedMinOrMaxSSE2<double, SSEWrapperMaxDouble>(
2734
0
                papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
2735
0
            return CE_None;
2736
0
        }
2737
0
    }
2738
0
#endif
2739
2740
0
    return MinOrMaxPixelFunc<Comparator>(dfK, papoSources, nSources, pData,
2741
0
                                         nXSize, nYSize, eSrcType, eBufType,
2742
0
                                         nPixelSpace, nLineSpace, papszArgs);
2743
0
}
2744
2745
static const char pszExprPixelFuncMetadata[] =
2746
    "<PixelFunctionArgumentsList>"
2747
    "   <Argument name='expression' "
2748
    "             description='Expression to be evaluated' "
2749
    "             type='string'></Argument>"
2750
    "   <Argument name='dialect' "
2751
    "             description='Expression dialect' "
2752
    "             type='string-select'"
2753
    "             default='muparser'>"
2754
    "       <Value>exprtk</Value>"
2755
    "       <Value>muparser</Value>"
2756
    "   </Argument>"
2757
    "   <Argument type='builtin' value='source_names' />"
2758
    "   <Argument type='builtin' value='xoff' />"
2759
    "   <Argument type='builtin' value='yoff' />"
2760
    "   <Argument type='builtin' value='geotransform' />"
2761
    "</PixelFunctionArgumentsList>";
2762
2763
static CPLErr ExprPixelFunc(void **papoSources, int nSources, void *pData,
2764
                            int nXSize, int nYSize, GDALDataType eSrcType,
2765
                            GDALDataType eBufType, int nPixelSpace,
2766
                            int nLineSpace, CSLConstList papszArgs)
2767
0
{
2768
    /* ---- Init ---- */
2769
2770
0
    if (GDALDataTypeIsComplex(eSrcType))
2771
0
    {
2772
0
        CPLError(CE_Failure, CPLE_AppDefined,
2773
0
                 "expression cannot by applied to complex data types");
2774
0
        return CE_Failure;
2775
0
    }
2776
2777
0
    std::unique_ptr<gdal::MathExpression> poExpression;
2778
2779
0
    const char *pszExpression = CSLFetchNameValue(papszArgs, "expression");
2780
2781
0
    const char *pszSourceNames = CSLFetchNameValue(papszArgs, "source_names");
2782
0
    const CPLStringList aosSourceNames(
2783
0
        CSLTokenizeString2(pszSourceNames, "|", 0));
2784
0
    if (aosSourceNames.size() != nSources)
2785
0
    {
2786
0
        CPLError(CE_Failure, CPLE_AppDefined,
2787
0
                 "The source_names variable passed to ExprPixelFunc() has %d "
2788
0
                 "values, whereas %d were expected. An invalid variable name "
2789
0
                 "has likely been used",
2790
0
                 aosSourceNames.size(), nSources);
2791
0
        return CE_Failure;
2792
0
    }
2793
2794
0
    std::vector<double> adfValuesForPixel(nSources);
2795
2796
0
    const char *pszDialect = CSLFetchNameValue(papszArgs, "dialect");
2797
0
    if (!pszDialect)
2798
0
    {
2799
0
        pszDialect = "muparser";
2800
0
    }
2801
2802
0
    poExpression = gdal::MathExpression::Create(pszExpression, pszDialect);
2803
2804
    // cppcheck-suppress knownConditionTrueFalse
2805
0
    if (!poExpression)
2806
0
    {
2807
0
        return CE_Failure;
2808
0
    }
2809
2810
0
    int nXOff = 0;
2811
0
    int nYOff = 0;
2812
0
    std::array<double, 6> gt;
2813
0
    double dfCenterX = 0;
2814
0
    double dfCenterY = 0;
2815
2816
0
    bool includeCenterCoords = false;
2817
0
    if (strstr(pszExpression, "_CENTER_X_") ||
2818
0
        strstr(pszExpression, "_CENTER_Y_"))
2819
0
    {
2820
0
        includeCenterCoords = true;
2821
2822
0
        const char *pszXOff = CSLFetchNameValue(papszArgs, "xoff");
2823
0
        nXOff = std::atoi(pszXOff);
2824
2825
0
        const char *pszYOff = CSLFetchNameValue(papszArgs, "yoff");
2826
0
        nYOff = std::atoi(pszYOff);
2827
2828
0
        const char *pszGT = CSLFetchNameValue(papszArgs, "geotransform");
2829
0
        if (pszGT == nullptr)
2830
0
        {
2831
0
            CPLError(CE_Failure, CPLE_AppDefined,
2832
0
                     "To use _CENTER_X_ or _CENTER_Y_ in an expression, "
2833
0
                     "VRTDataset must have a <GeoTransform> element.");
2834
0
            return CE_Failure;
2835
0
        }
2836
2837
0
        CPLStringList aosGeoTransform(
2838
0
            CSLTokenizeString2(pszGT, ",", CSLT_HONOURSTRINGS));
2839
0
        if (aosGeoTransform.size() != 6)
2840
0
        {
2841
0
            CPLError(CE_Failure, CPLE_AppDefined,
2842
0
                     "Invalid GeoTransform argument");
2843
0
            return CE_Failure;
2844
0
        }
2845
0
        for (int i = 0; i < 6; i++)
2846
0
        {
2847
0
            gt[i] = CPLAtof(aosGeoTransform[i]);
2848
0
        }
2849
0
    }
2850
2851
0
    {
2852
0
        int iSource = 0;
2853
0
        for (const auto &osName : aosSourceNames)
2854
0
        {
2855
0
            poExpression->RegisterVariable(osName,
2856
0
                                           &adfValuesForPixel[iSource++]);
2857
0
        }
2858
0
    }
2859
2860
0
    if (includeCenterCoords)
2861
0
    {
2862
0
        poExpression->RegisterVariable("_CENTER_X_", &dfCenterX);
2863
0
        poExpression->RegisterVariable("_CENTER_Y_", &dfCenterY);
2864
0
    }
2865
2866
0
    if (strstr(pszExpression, "BANDS"))
2867
0
    {
2868
0
        poExpression->RegisterVector("BANDS", &adfValuesForPixel);
2869
0
    }
2870
2871
0
    std::unique_ptr<double, VSIFreeReleaser> padfResults(
2872
0
        static_cast<double *>(VSI_MALLOC2_VERBOSE(nXSize, sizeof(double))));
2873
0
    if (!padfResults)
2874
0
        return CE_Failure;
2875
2876
    /* ---- Set pixels ---- */
2877
0
    size_t ii = 0;
2878
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
2879
0
    {
2880
0
        for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
2881
0
        {
2882
0
            for (int iSrc = 0; iSrc < nSources; iSrc++)
2883
0
            {
2884
                // cppcheck-suppress unreadVariable
2885
0
                adfValuesForPixel[iSrc] =
2886
0
                    GetSrcVal(papoSources[iSrc], eSrcType, ii);
2887
0
            }
2888
2889
0
            if (includeCenterCoords)
2890
0
            {
2891
                // Add 0.5 to pixel / line to move from pixel corner to cell center
2892
0
                GDALApplyGeoTransform(gt.data(),
2893
0
                                      static_cast<double>(iCol + nXOff) + 0.5,
2894
0
                                      static_cast<double>(iLine + nYOff) + 0.5,
2895
0
                                      &dfCenterX, &dfCenterY);
2896
0
            }
2897
2898
0
            if (auto eErr = poExpression->Evaluate(); eErr != CE_None)
2899
0
            {
2900
0
                return CE_Failure;
2901
0
            }
2902
0
            else
2903
0
            {
2904
0
                padfResults.get()[iCol] = poExpression->Results()[0];
2905
0
            }
2906
0
        }
2907
2908
0
        GDALCopyWords(padfResults.get(), GDT_Float64, sizeof(double),
2909
0
                      static_cast<GByte *>(pData) +
2910
0
                          static_cast<GSpacing>(nLineSpace) * iLine,
2911
0
                      eBufType, nPixelSpace, nXSize);
2912
0
    }
2913
2914
    /* ---- Return success ---- */
2915
0
    return CE_None;
2916
0
}  // ExprPixelFunc
2917
2918
static const char pszReclassifyPixelFuncMetadata[] =
2919
    "<PixelFunctionArgumentsList>"
2920
    "   <Argument name='mapping' "
2921
    "             description='Lookup table for mapping, in format "
2922
    "from=to,from=to' "
2923
    "             type='string'></Argument>"
2924
    "   <Argument type='builtin' value='NoData' optional='true' />"
2925
    "</PixelFunctionArgumentsList>";
2926
2927
static CPLErr ReclassifyPixelFunc(void **papoSources, int nSources, void *pData,
2928
                                  int nXSize, int nYSize, GDALDataType eSrcType,
2929
                                  GDALDataType eBufType, int nPixelSpace,
2930
                                  int nLineSpace, CSLConstList papszArgs)
2931
0
{
2932
0
    if (GDALDataTypeIsComplex(eSrcType))
2933
0
    {
2934
0
        CPLError(CE_Failure, CPLE_AppDefined,
2935
0
                 "reclassify cannot by applied to complex data types");
2936
0
        return CE_Failure;
2937
0
    }
2938
2939
0
    if (nSources != 1)
2940
0
    {
2941
0
        CPLError(CE_Failure, CPLE_AppDefined,
2942
0
                 "reclassify only be applied to a single source at a time");
2943
0
        return CE_Failure;
2944
0
    }
2945
0
    std::optional<double> noDataValue{};
2946
2947
0
    const char *pszNoData = CSLFetchNameValue(papszArgs, "NoData");
2948
0
    if (pszNoData != nullptr)
2949
0
    {
2950
0
        noDataValue = CPLAtof(pszNoData);
2951
0
    }
2952
2953
0
    const char *pszMappings = CSLFetchNameValue(papszArgs, "mapping");
2954
0
    if (pszMappings == nullptr)
2955
0
    {
2956
0
        CPLError(CE_Failure, CPLE_AppDefined,
2957
0
                 "reclassify must be called with 'mapping' argument");
2958
0
        return CE_Failure;
2959
0
    }
2960
2961
0
    gdal::Reclassifier oReclassifier;
2962
0
    if (auto eErr = oReclassifier.Init(pszMappings, noDataValue, eBufType);
2963
0
        eErr != CE_None)
2964
0
    {
2965
0
        return eErr;
2966
0
    }
2967
2968
0
    std::unique_ptr<double, VSIFreeReleaser> padfResults(
2969
0
        static_cast<double *>(VSI_MALLOC2_VERBOSE(nXSize, sizeof(double))));
2970
0
    if (!padfResults)
2971
0
        return CE_Failure;
2972
2973
0
    size_t ii = 0;
2974
0
    bool bSuccess = false;
2975
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
2976
0
    {
2977
0
        for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
2978
0
        {
2979
0
            double srcVal = GetSrcVal(papoSources[0], eSrcType, ii);
2980
0
            padfResults.get()[iCol] =
2981
0
                oReclassifier.Reclassify(srcVal, bSuccess);
2982
0
            if (!bSuccess)
2983
0
            {
2984
0
                CPLError(CE_Failure, CPLE_AppDefined,
2985
0
                         "Encountered value %g with no specified mapping",
2986
0
                         srcVal);
2987
0
                return CE_Failure;
2988
0
            }
2989
0
        }
2990
2991
0
        GDALCopyWords(padfResults.get(), GDT_Float64, sizeof(double),
2992
0
                      static_cast<GByte *>(pData) +
2993
0
                          static_cast<GSpacing>(nLineSpace) * iLine,
2994
0
                      eBufType, nPixelSpace, nXSize);
2995
0
    }
2996
2997
0
    return CE_None;
2998
0
}  // ReclassifyPixelFunc
2999
3000
struct MeanKernel
3001
{
3002
    static constexpr const char *pszName = "mean";
3003
3004
    double dfMean = 0;
3005
    int nValidSources = 0;
3006
3007
    void Reset()
3008
0
    {
3009
0
        dfMean = 0;
3010
0
        nValidSources = 0;
3011
0
    }
3012
3013
    static CPLErr ProcessArguments(CSLConstList)
3014
0
    {
3015
0
        return CE_None;
3016
0
    }
3017
3018
    void ProcessPixel(double dfVal)
3019
0
    {
3020
0
        ++nValidSources;
3021
3022
0
        if (CPL_UNLIKELY(std::isinf(dfVal)))
3023
0
        {
3024
0
            if (nValidSources == 1)
3025
0
            {
3026
0
                dfMean = dfVal;
3027
0
            }
3028
0
            else if (dfVal == -dfMean)
3029
0
            {
3030
0
                dfMean = std::numeric_limits<double>::quiet_NaN();
3031
0
            }
3032
0
        }
3033
0
        else if (CPL_UNLIKELY(std::isinf(dfMean)))
3034
0
        {
3035
0
            if (!std::isfinite(dfVal))
3036
0
            {
3037
0
                dfMean = std::numeric_limits<double>::quiet_NaN();
3038
0
            }
3039
0
        }
3040
0
        else
3041
0
        {
3042
0
            const double delta = dfVal - dfMean;
3043
0
            if (CPL_UNLIKELY(std::isinf(delta)))
3044
0
                dfMean += dfVal / nValidSources - dfMean / nValidSources;
3045
0
            else
3046
0
                dfMean += delta / nValidSources;
3047
0
        }
3048
0
    }
3049
3050
    bool HasValue() const
3051
0
    {
3052
0
        return nValidSources > 0;
3053
0
    }
3054
3055
    double GetValue() const
3056
0
    {
3057
0
        return dfMean;
3058
0
    }
3059
};
3060
3061
struct GeoMeanKernel
3062
{
3063
    static constexpr const char *pszName = "geometric_mean";
3064
3065
    double dfProduct = 1;
3066
    int nValidSources = 0;
3067
3068
    void Reset()
3069
0
    {
3070
0
        dfProduct = 1;
3071
0
        nValidSources = 0;
3072
0
    }
3073
3074
    static CPLErr ProcessArguments(CSLConstList)
3075
0
    {
3076
0
        return CE_None;
3077
0
    }
3078
3079
    void ProcessPixel(double dfVal)
3080
0
    {
3081
0
        dfProduct *= dfVal;
3082
0
        nValidSources++;
3083
0
    }
3084
3085
    bool HasValue() const
3086
0
    {
3087
0
        return nValidSources > 0;
3088
0
    }
3089
3090
    double GetValue() const
3091
0
    {
3092
0
        return std::pow(dfProduct, 1.0 / nValidSources);
3093
0
    }
3094
};
3095
3096
struct HarmonicMeanKernel
3097
{
3098
    static constexpr const char *pszName = "harmonic_mean";
3099
3100
    double dfDenom = 0;
3101
    int nValidSources = 0;
3102
    bool bValueIsZero = false;
3103
    bool bPropagateZero = false;
3104
3105
    void Reset()
3106
0
    {
3107
0
        dfDenom = 0;
3108
0
        nValidSources = 0;
3109
0
        bValueIsZero = false;
3110
0
    }
3111
3112
    void ProcessPixel(double dfVal)
3113
0
    {
3114
0
        if (dfVal == 0)
3115
0
        {
3116
0
            bValueIsZero = true;
3117
0
        }
3118
0
        else
3119
0
        {
3120
0
            dfDenom += 1 / dfVal;
3121
0
        }
3122
0
        nValidSources++;
3123
0
    }
3124
3125
    CPLErr ProcessArguments(CSLConstList papszArgs)
3126
0
    {
3127
0
        bPropagateZero =
3128
0
            CPLTestBool(CSLFetchNameValueDef(papszArgs, "propagateZero", "0"));
3129
0
        return CE_None;
3130
0
    }
3131
3132
    bool HasValue() const
3133
0
    {
3134
0
        return dfDenom > 0 && (bPropagateZero || !bValueIsZero);
3135
0
    }
3136
3137
    double GetValue() const
3138
0
    {
3139
0
        if (bPropagateZero && bValueIsZero)
3140
0
        {
3141
0
            return 0;
3142
0
        }
3143
0
        return static_cast<double>(nValidSources) / dfDenom;
3144
0
    }
3145
};
3146
3147
struct MedianKernel
3148
{
3149
    static constexpr const char *pszName = "median";
3150
3151
    mutable std::vector<double> values{};
3152
3153
    void Reset()
3154
0
    {
3155
0
        values.clear();
3156
0
    }
3157
3158
    static CPLErr ProcessArguments(CSLConstList)
3159
0
    {
3160
0
        return CE_None;
3161
0
    }
3162
3163
    void ProcessPixel(double dfVal)
3164
0
    {
3165
0
        if (!std::isnan(dfVal))
3166
0
        {
3167
0
            values.push_back(dfVal);
3168
0
        }
3169
0
    }
3170
3171
    bool HasValue() const
3172
0
    {
3173
0
        return !values.empty();
3174
0
    }
3175
3176
    double GetValue() const
3177
0
    {
3178
0
        std::sort(values.begin(), values.end());
3179
0
        if (values.size() % 2 == 0)
3180
0
        {
3181
0
            return 0.5 *
3182
0
                   (values[values.size() / 2 - 1] + values[values.size() / 2]);
3183
0
        }
3184
3185
0
        return values[values.size() / 2];
3186
0
    }
3187
};
3188
3189
struct ModeKernel
3190
{
3191
    static constexpr const char *pszName = "mode";
3192
3193
    std::map<double, size_t> counts{};
3194
    std::size_t nanCount{0};
3195
    double dfMax = std::numeric_limits<double>::quiet_NaN();
3196
    decltype(counts.begin()) oMax = counts.end();
3197
3198
    void Reset()
3199
0
    {
3200
0
        nanCount = 0;
3201
0
        counts.clear();
3202
0
        oMax = counts.end();
3203
0
    }
3204
3205
    static CPLErr ProcessArguments(CSLConstList)
3206
0
    {
3207
0
        return CE_None;
3208
0
    }
3209
3210
    void ProcessPixel(double dfVal)
3211
0
    {
3212
0
        if (std::isnan(dfVal))
3213
0
        {
3214
0
            nanCount += 1;
3215
0
            return;
3216
0
        }
3217
3218
        // if dfVal is NaN, try_emplace will return an entry for a different key!
3219
0
        auto [it, inserted] = counts.try_emplace(dfVal, 0);
3220
3221
0
        it->second += 1;
3222
3223
0
        if (oMax == counts.end() || it->second > oMax->second)
3224
0
        {
3225
0
            oMax = it;
3226
0
        }
3227
0
    }
3228
3229
    bool HasValue() const
3230
0
    {
3231
0
        return nanCount > 0 || oMax != counts.end();
3232
0
    }
3233
3234
    double GetValue() const
3235
0
    {
3236
0
        double ret = std::numeric_limits<double>::quiet_NaN();
3237
0
        if (oMax != counts.end())
3238
0
        {
3239
0
            const size_t nCount = oMax->second;
3240
0
            if (nCount > nanCount)
3241
0
                ret = oMax->first;
3242
0
        }
3243
0
        return ret;
3244
0
    }
3245
};
3246
3247
static const char pszBasicPixelFuncMetadata[] =
3248
    "<PixelFunctionArgumentsList>"
3249
    "   <Argument type='builtin' value='NoData' optional='true' />"
3250
    "   <Argument name='propagateNoData' description='Whether the output value "
3251
    "should be NoData as as soon as one source is NoData' type='boolean' "
3252
    "default='false' />"
3253
    "</PixelFunctionArgumentsList>";
3254
3255
#if defined(USE_SSE2) && !defined(USE_NEON_OPTIMIZATIONS)
3256
inline __m128i packus_epi32(__m128i low, __m128i high)
3257
0
{
3258
#if __SSE4_1__
3259
    return _mm_packus_epi32(low, high);  // Pack uint32 to uint16
3260
#else
3261
0
    low = _mm_add_epi32(low, _mm_set1_epi32(-32768));
3262
0
    high = _mm_add_epi32(high, _mm_set1_epi32(-32768));
3263
0
    return _mm_sub_epi16(_mm_packs_epi32(low, high), _mm_set1_epi16(-32768));
3264
0
#endif
3265
0
}
3266
#endif
3267
3268
#ifdef USE_SSE2
3269
3270
template <class T, class SSEWrapper>
3271
static void OptimizedMeanFloatSSE2(const void *const *papoSources, int nSources,
3272
                                   void *pData, int nXSize, int nYSize,
3273
                                   int nLineSpace)
3274
0
{
3275
0
    assert(nSources >= 1);
3276
0
    constexpr int VALUES_PER_REG =
3277
0
        static_cast<int>(sizeof(typename SSEWrapper::Vec) / sizeof(T));
3278
0
    const T invSources = static_cast<T>(1.0) / static_cast<T>(nSources);
3279
0
    const auto invSourcesSSE = SSEWrapper::Set1(invSources);
3280
0
    const auto signMaskSSE = SSEWrapper::Set1(static_cast<T>(-0.0));
3281
0
    const auto infSSE = SSEWrapper::Set1(std::numeric_limits<T>::infinity());
3282
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
3283
0
    {
3284
0
        T *CPL_RESTRICT pDest =
3285
0
            reinterpret_cast<T *>(static_cast<GByte *>(pData) +
3286
0
                                  static_cast<GSpacing>(nLineSpace) * iLine);
3287
0
        const size_t iOffsetLine = static_cast<size_t>(iLine) * nXSize;
3288
0
        int iCol = 0;
3289
0
        for (; iCol < nXSize - (2 * VALUES_PER_REG - 1);
3290
0
             iCol += 2 * VALUES_PER_REG)
3291
0
        {
3292
0
            auto reg0 = SSEWrapper::LoadU(
3293
0
                static_cast<const T * CPL_RESTRICT>(papoSources[0]) +
3294
0
                iOffsetLine + iCol);
3295
0
            auto reg1 = SSEWrapper::LoadU(
3296
0
                static_cast<const T * CPL_RESTRICT>(papoSources[0]) +
3297
0
                iOffsetLine + iCol + VALUES_PER_REG);
3298
0
            for (int iSrc = 1; iSrc < nSources; ++iSrc)
3299
0
            {
3300
0
                const auto inputVal0 = SSEWrapper::LoadU(
3301
0
                    static_cast<const T * CPL_RESTRICT>(papoSources[iSrc]) +
3302
0
                    iOffsetLine + iCol);
3303
0
                const auto inputVal1 = SSEWrapper::LoadU(
3304
0
                    static_cast<const T * CPL_RESTRICT>(papoSources[iSrc]) +
3305
0
                    iOffsetLine + iCol + VALUES_PER_REG);
3306
0
                reg0 = SSEWrapper::Add(reg0, inputVal0);
3307
0
                reg1 = SSEWrapper::Add(reg1, inputVal1);
3308
0
            }
3309
0
            reg0 = SSEWrapper::Mul(reg0, invSourcesSSE);
3310
0
            reg1 = SSEWrapper::Mul(reg1, invSourcesSSE);
3311
3312
            // Detect infinity that could happen when summing huge
3313
            // values
3314
0
            if (SSEWrapper::MoveMask(SSEWrapper::Or(
3315
0
                    SSEWrapper::CmpEq(SSEWrapper::AndNot(signMaskSSE, reg0),
3316
0
                                      infSSE),
3317
0
                    SSEWrapper::CmpEq(SSEWrapper::AndNot(signMaskSSE, reg1),
3318
0
                                      infSSE))))
3319
0
            {
3320
0
                break;
3321
0
            }
3322
3323
0
            SSEWrapper::StoreU(pDest + iCol, reg0);
3324
0
            SSEWrapper::StoreU(pDest + iCol + VALUES_PER_REG, reg1);
3325
0
        }
3326
3327
        // Use numerically stable mean computation
3328
0
        for (; iCol < nXSize; ++iCol)
3329
0
        {
3330
0
            T mean = static_cast<const T * CPL_RESTRICT>(
3331
0
                papoSources[0])[iOffsetLine + iCol];
3332
0
            if (nSources >= 2)
3333
0
            {
3334
0
                T new_val = static_cast<const T * CPL_RESTRICT>(
3335
0
                    papoSources[1])[iOffsetLine + iCol];
3336
0
                if (CPL_UNLIKELY(std::isinf(new_val)))
3337
0
                {
3338
0
                    if (new_val == -mean)
3339
0
                    {
3340
0
                        pDest[iCol] = std::numeric_limits<T>::quiet_NaN();
3341
0
                        continue;
3342
0
                    }
3343
0
                }
3344
0
                else if (CPL_UNLIKELY(std::isinf(mean)))
3345
0
                {
3346
0
                    if (!std::isfinite(new_val))
3347
0
                    {
3348
0
                        pDest[iCol] = std::numeric_limits<T>::quiet_NaN();
3349
0
                        continue;
3350
0
                    }
3351
0
                }
3352
0
                else
3353
0
                {
3354
0
                    const T delta = new_val - mean;
3355
0
                    if (CPL_UNLIKELY(std::isinf(delta)))
3356
0
                        mean += new_val * static_cast<T>(0.5) -
3357
0
                                mean * static_cast<T>(0.5);
3358
0
                    else
3359
0
                        mean += delta * static_cast<T>(0.5);
3360
0
                }
3361
3362
0
                for (int iSrc = 2; iSrc < nSources; ++iSrc)
3363
0
                {
3364
0
                    new_val = static_cast<const T * CPL_RESTRICT>(
3365
0
                        papoSources[iSrc])[iOffsetLine + iCol];
3366
0
                    if (CPL_UNLIKELY(std::isinf(new_val)))
3367
0
                    {
3368
0
                        if (new_val == -mean)
3369
0
                        {
3370
0
                            mean = std::numeric_limits<T>::quiet_NaN();
3371
0
                            break;
3372
0
                        }
3373
0
                    }
3374
0
                    else if (CPL_UNLIKELY(std::isinf(mean)))
3375
0
                    {
3376
0
                        if (!std::isfinite(new_val))
3377
0
                        {
3378
0
                            mean = std::numeric_limits<T>::quiet_NaN();
3379
0
                            break;
3380
0
                        }
3381
0
                    }
3382
0
                    else
3383
0
                    {
3384
0
                        const T delta = new_val - mean;
3385
0
                        if (CPL_UNLIKELY(std::isinf(delta)))
3386
0
                            mean += new_val / static_cast<T>(iSrc + 1) -
3387
0
                                    mean / static_cast<T>(iSrc + 1);
3388
0
                        else
3389
0
                            mean += delta / static_cast<T>(iSrc + 1);
3390
0
                    }
3391
0
                }
3392
0
            }
3393
0
            pDest[iCol] = mean;
3394
0
        }
3395
0
    }
3396
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)
3397
3398
// clang-format off
3399
namespace
3400
{
3401
#ifdef __AVX2__
3402
struct SSEWrapperFloat
3403
{
3404
    typedef __m256 Vec;
3405
3406
    static inline Vec Set1(float x) { return _mm256_set1_ps(x); }
3407
    static inline Vec LoadU(const float *x) { return _mm256_loadu_ps(x); }
3408
    static inline void StoreU(float *x, Vec y) { _mm256_storeu_ps(x, y); }
3409
    static inline Vec Add(Vec x, Vec y) { return _mm256_add_ps(x, y); }
3410
    static inline Vec Mul(Vec x, Vec y) { return _mm256_mul_ps(x, y); }
3411
    static inline Vec Or(Vec x, Vec y) { return _mm256_or_ps(x, y); }
3412
    static inline Vec AndNot(Vec x, Vec y) { return _mm256_andnot_ps(x, y); }
3413
    static inline Vec CmpEq(Vec x, Vec y) { return _mm256_cmp_ps(x, y, _CMP_EQ_OQ); }
3414
    static inline int MoveMask(Vec x) { return _mm256_movemask_ps(x); }
3415
};
3416
3417
struct SSEWrapperDouble
3418
{
3419
    typedef __m256d Vec;
3420
3421
    static inline Vec Set1(double x) { return _mm256_set1_pd(x); }
3422
    static inline Vec LoadU(const double *x) { return _mm256_loadu_pd(x); }
3423
    static inline void StoreU(double *x, Vec y) { _mm256_storeu_pd(x, y); }
3424
    static inline Vec Add(Vec x, Vec y) { return _mm256_add_pd(x, y); }
3425
    static inline Vec Mul(Vec x, Vec y) { return _mm256_mul_pd(x, y); }
3426
    static inline Vec Or(Vec x, Vec y) { return _mm256_or_pd(x, y); }
3427
    static inline Vec AndNot(Vec x, Vec y) { return _mm256_andnot_pd(x, y); }
3428
    static inline Vec CmpEq(Vec x, Vec y) { return _mm256_cmp_pd(x, y, _CMP_EQ_OQ); }
3429
    static inline int MoveMask(Vec x) { return _mm256_movemask_pd(x); }
3430
};
3431
3432
#else
3433
3434
struct SSEWrapperFloat
3435
{
3436
    typedef __m128 Vec;
3437
3438
0
    static inline Vec Set1(float x) { return _mm_set1_ps(x); }
3439
0
    static inline Vec LoadU(const float *x) { return _mm_loadu_ps(x); }
3440
0
    static inline void StoreU(float *x, Vec y) { _mm_storeu_ps(x, y); }
3441
0
    static inline Vec Add(Vec x, Vec y) { return _mm_add_ps(x, y); }
3442
0
    static inline Vec Mul(Vec x, Vec y) { return _mm_mul_ps(x, y); }
3443
0
    static inline Vec Or(Vec x, Vec y) { return _mm_or_ps(x, y); }
3444
0
    static inline Vec AndNot(Vec x, Vec y) { return _mm_andnot_ps(x, y); }
3445
0
    static inline Vec CmpEq(Vec x, Vec y) { return _mm_cmpeq_ps(x, y); }
3446
0
    static inline int MoveMask(Vec x) { return _mm_movemask_ps(x); }
3447
};
3448
3449
struct SSEWrapperDouble
3450
{
3451
    typedef __m128d Vec;
3452
3453
0
    static inline Vec Set1(double x) { return _mm_set1_pd(x); }
3454
0
    static inline Vec LoadU(const double *x) { return _mm_loadu_pd(x); }
3455
0
    static inline void StoreU(double *x, Vec y) { _mm_storeu_pd(x, y); }
3456
0
    static inline Vec Add(Vec x, Vec y) { return _mm_add_pd(x, y); }
3457
0
    static inline Vec Mul(Vec x, Vec y) { return _mm_mul_pd(x, y); }
3458
0
    static inline Vec Or(Vec x, Vec y) { return _mm_or_pd(x, y); }
3459
0
    static inline Vec AndNot(Vec x, Vec y) { return _mm_andnot_pd(x, y); }
3460
0
    static inline Vec CmpEq(Vec x, Vec y) { return _mm_cmpeq_pd(x, y); }
3461
0
    static inline int MoveMask(Vec x) { return _mm_movemask_pd(x); }
3462
};
3463
#endif
3464
}  // namespace
3465
3466
// clang-format on
3467
3468
#endif  // USE_SSE2
3469
3470
template <typename Kernel>
3471
static CPLErr BasicPixelFunc(void **papoSources, int nSources, void *pData,
3472
                             int nXSize, int nYSize, GDALDataType eSrcType,
3473
                             GDALDataType eBufType, int nPixelSpace,
3474
                             int nLineSpace, CSLConstList papszArgs)
3475
0
{
3476
    /* ---- Init ---- */
3477
0
    Kernel oKernel;
3478
3479
0
    if (GDALDataTypeIsComplex(eSrcType))
3480
0
    {
3481
0
        CPLError(CE_Failure, CPLE_AppDefined,
3482
0
                 "Complex data types not supported by %s", oKernel.pszName);
3483
0
        return CE_Failure;
3484
0
    }
3485
3486
0
    double dfNoData{0};
3487
0
    const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
3488
0
    if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)
3489
0
        return CE_Failure;
3490
3491
0
    const bool bPropagateNoData = CPLTestBool(
3492
0
        CSLFetchNameValueDef(papszArgs, "propagateNoData", "false"));
3493
3494
0
    if (oKernel.ProcessArguments(papszArgs) == CE_Failure)
3495
0
    {
3496
0
        return CE_Failure;
3497
0
    }
3498
3499
0
#if defined(USE_SSE2) && !defined(USE_NEON_OPTIMIZATIONS)
3500
    if constexpr (std::is_same_v<Kernel, MeanKernel>)
3501
0
    {
3502
0
        if (!bHasNoData && eSrcType == GDT_Byte && eBufType == GDT_Byte &&
3503
0
            nPixelSpace == 1 &&
3504
            // We use signed int16 to accumulate
3505
0
            nSources <= std::numeric_limits<int16_t>::max() /
3506
0
                            std::numeric_limits<uint8_t>::max())
3507
0
        {
3508
0
            using T = uint8_t;
3509
0
            constexpr int VALUES_PER_REG = 16;
3510
0
            if (nSources == 2)
3511
0
            {
3512
0
                for (int iLine = 0; iLine < nYSize; ++iLine)
3513
0
                {
3514
0
                    T *CPL_RESTRICT pDest = reinterpret_cast<T *>(
3515
0
                        static_cast<GByte *>(pData) +
3516
0
                        static_cast<GSpacing>(nLineSpace) * iLine);
3517
0
                    const size_t iOffsetLine =
3518
0
                        static_cast<size_t>(iLine) * nXSize;
3519
0
                    int iCol = 0;
3520
0
                    for (; iCol < nXSize - (VALUES_PER_REG - 1);
3521
0
                         iCol += VALUES_PER_REG)
3522
0
                    {
3523
0
                        const __m128i inputVal0 =
3524
0
                            _mm_loadu_si128(reinterpret_cast<const __m128i *>(
3525
0
                                static_cast<const T * CPL_RESTRICT>(
3526
0
                                    papoSources[0]) +
3527
0
                                iOffsetLine + iCol));
3528
0
                        const __m128i inputVal1 =
3529
0
                            _mm_loadu_si128(reinterpret_cast<const __m128i *>(
3530
0
                                static_cast<const T * CPL_RESTRICT>(
3531
0
                                    papoSources[1]) +
3532
0
                                iOffsetLine + iCol));
3533
0
                        _mm_storeu_si128(
3534
0
                            reinterpret_cast<__m128i *>(pDest + iCol),
3535
0
                            _mm_avg_epu8(inputVal0, inputVal1));
3536
0
                    }
3537
0
                    for (; iCol < nXSize; ++iCol)
3538
0
                    {
3539
0
                        uint32_t acc = 1 +
3540
0
                                       static_cast<const T * CPL_RESTRICT>(
3541
0
                                           papoSources[0])[iOffsetLine + iCol] +
3542
0
                                       static_cast<const T * CPL_RESTRICT>(
3543
0
                                           papoSources[1])[iOffsetLine + iCol];
3544
0
                        pDest[iCol] = static_cast<T>(acc / 2);
3545
0
                    }
3546
0
                }
3547
0
            }
3548
0
            else
3549
0
            {
3550
0
                libdivide::divider<uint16_t> fast_d(
3551
0
                    static_cast<uint16_t>(nSources));
3552
0
                const auto halfConstant =
3553
0
                    _mm_set1_epi16(static_cast<int16_t>(nSources / 2));
3554
0
                for (int iLine = 0; iLine < nYSize; ++iLine)
3555
0
                {
3556
0
                    T *CPL_RESTRICT pDest =
3557
0
                        static_cast<GByte *>(pData) +
3558
0
                        static_cast<GSpacing>(nLineSpace) * iLine;
3559
0
                    const size_t iOffsetLine =
3560
0
                        static_cast<size_t>(iLine) * nXSize;
3561
0
                    int iCol = 0;
3562
0
                    for (; iCol < nXSize - (VALUES_PER_REG - 1);
3563
0
                         iCol += VALUES_PER_REG)
3564
0
                    {
3565
0
                        __m128i reg0 = halfConstant;
3566
0
                        __m128i reg1 = halfConstant;
3567
0
                        for (int iSrc = 0; iSrc < nSources; ++iSrc)
3568
0
                        {
3569
0
                            const __m128i inputVal = _mm_loadu_si128(
3570
0
                                reinterpret_cast<const __m128i *>(
3571
0
                                    static_cast<const T * CPL_RESTRICT>(
3572
0
                                        papoSources[iSrc]) +
3573
0
                                    iOffsetLine + iCol));
3574
0
                            reg0 = _mm_add_epi16(
3575
0
                                reg0, _mm_unpacklo_epi8(inputVal,
3576
0
                                                        _mm_setzero_si128()));
3577
0
                            reg1 = _mm_add_epi16(
3578
0
                                reg1, _mm_unpackhi_epi8(inputVal,
3579
0
                                                        _mm_setzero_si128()));
3580
0
                        }
3581
0
                        reg0 /= fast_d;
3582
0
                        reg1 /= fast_d;
3583
0
                        _mm_storeu_si128(
3584
0
                            reinterpret_cast<__m128i *>(pDest + iCol),
3585
0
                            _mm_packus_epi16(reg0, reg1));
3586
0
                    }
3587
0
                    for (; iCol < nXSize; ++iCol)
3588
0
                    {
3589
0
                        uint32_t acc = nSources / 2;
3590
0
                        for (int iSrc = 0; iSrc < nSources; ++iSrc)
3591
0
                        {
3592
0
                            acc += static_cast<const T * CPL_RESTRICT>(
3593
0
                                papoSources[iSrc])[iOffsetLine + iCol];
3594
0
                        }
3595
0
                        pDest[iCol] = static_cast<T>(acc / nSources);
3596
0
                    }
3597
0
                }
3598
0
            }
3599
0
            return CE_None;
3600
0
        }
3601
3602
0
        if (!bHasNoData && eSrcType == GDT_Byte && eBufType == GDT_Byte &&
3603
0
            nPixelSpace == 1 &&
3604
            // We use signed int32 to accumulate
3605
0
            nSources <= std::numeric_limits<int32_t>::max() /
3606
0
                            std::numeric_limits<uint8_t>::max())
3607
0
        {
3608
0
            using T = uint8_t;
3609
0
            constexpr int VALUES_PER_REG = 16;
3610
0
            libdivide::divider<uint32_t> fast_d(nSources);
3611
0
            const auto halfConstant = _mm_set1_epi32(nSources / 2);
3612
0
            for (int iLine = 0; iLine < nYSize; ++iLine)
3613
0
            {
3614
0
                T *CPL_RESTRICT pDest =
3615
0
                    static_cast<GByte *>(pData) +
3616
0
                    static_cast<GSpacing>(nLineSpace) * iLine;
3617
0
                const size_t iOffsetLine = static_cast<size_t>(iLine) * nXSize;
3618
0
                int iCol = 0;
3619
0
                for (; iCol < nXSize - (VALUES_PER_REG - 1);
3620
0
                     iCol += VALUES_PER_REG)
3621
0
                {
3622
0
                    __m128i reg0 = halfConstant;
3623
0
                    __m128i reg1 = halfConstant;
3624
0
                    __m128i reg2 = halfConstant;
3625
0
                    __m128i reg3 = halfConstant;
3626
0
                    for (int iSrc = 0; iSrc < nSources; ++iSrc)
3627
0
                    {
3628
0
                        const __m128i inputVal =
3629
0
                            _mm_loadu_si128(reinterpret_cast<const __m128i *>(
3630
0
                                static_cast<const T * CPL_RESTRICT>(
3631
0
                                    papoSources[iSrc]) +
3632
0
                                iOffsetLine + iCol));
3633
0
                        const __m128i low =
3634
0
                            _mm_unpacklo_epi8(inputVal, _mm_setzero_si128());
3635
0
                        const __m128i high =
3636
0
                            _mm_unpackhi_epi8(inputVal, _mm_setzero_si128());
3637
0
                        reg0 = _mm_add_epi32(
3638
0
                            reg0, _mm_unpacklo_epi16(low, _mm_setzero_si128()));
3639
0
                        reg1 = _mm_add_epi32(
3640
0
                            reg1, _mm_unpackhi_epi16(low, _mm_setzero_si128()));
3641
0
                        reg2 = _mm_add_epi32(
3642
0
                            reg2,
3643
0
                            _mm_unpacklo_epi16(high, _mm_setzero_si128()));
3644
0
                        reg3 = _mm_add_epi32(
3645
0
                            reg3,
3646
0
                            _mm_unpackhi_epi16(high, _mm_setzero_si128()));
3647
0
                    }
3648
0
                    reg0 /= fast_d;
3649
0
                    reg1 /= fast_d;
3650
0
                    reg2 /= fast_d;
3651
0
                    reg3 /= fast_d;
3652
0
                    _mm_storeu_si128(
3653
0
                        reinterpret_cast<__m128i *>(pDest + iCol),
3654
0
                        _mm_packus_epi16(packus_epi32(reg0, reg1),
3655
0
                                         packus_epi32(reg2, reg3)));
3656
0
                }
3657
0
                for (; iCol < nXSize; ++iCol)
3658
0
                {
3659
0
                    uint32_t acc = nSources / 2;
3660
0
                    for (int iSrc = 0; iSrc < nSources; ++iSrc)
3661
0
                    {
3662
0
                        acc += static_cast<const T * CPL_RESTRICT>(
3663
0
                            papoSources[iSrc])[iOffsetLine + iCol];
3664
0
                    }
3665
0
                    pDest[iCol] = static_cast<T>(acc / nSources);
3666
0
                }
3667
0
            }
3668
0
            return CE_None;
3669
0
        }
3670
3671
0
        if (!bHasNoData && eSrcType == GDT_UInt16 && eBufType == GDT_UInt16 &&
3672
0
            nPixelSpace == 2 &&
3673
0
            nSources <= std::numeric_limits<int32_t>::max() /
3674
0
                            std::numeric_limits<uint16_t>::max())
3675
0
        {
3676
0
            libdivide::divider<uint32_t> fast_d(nSources);
3677
0
            using T = uint16_t;
3678
0
            const auto halfConstant = _mm_set1_epi32(nSources / 2);
3679
0
            constexpr int VALUES_PER_REG = 8;
3680
0
            for (int iLine = 0; iLine < nYSize; ++iLine)
3681
0
            {
3682
0
                T *CPL_RESTRICT pDest = reinterpret_cast<T *>(
3683
0
                    static_cast<GByte *>(pData) +
3684
0
                    static_cast<GSpacing>(nLineSpace) * iLine);
3685
0
                const size_t iOffsetLine = static_cast<size_t>(iLine) * nXSize;
3686
0
                int iCol = 0;
3687
0
                for (; iCol < nXSize - (VALUES_PER_REG - 1);
3688
0
                     iCol += VALUES_PER_REG)
3689
0
                {
3690
0
                    __m128i reg0 = halfConstant;
3691
0
                    __m128i reg1 = halfConstant;
3692
0
                    for (int iSrc = 0; iSrc < nSources; ++iSrc)
3693
0
                    {
3694
0
                        const __m128i inputVal =
3695
0
                            _mm_loadu_si128(reinterpret_cast<const __m128i *>(
3696
0
                                static_cast<const T * CPL_RESTRICT>(
3697
0
                                    papoSources[iSrc]) +
3698
0
                                iOffsetLine + iCol));
3699
0
                        reg0 = _mm_add_epi32(
3700
0
                            reg0,
3701
0
                            _mm_unpacklo_epi16(inputVal, _mm_setzero_si128()));
3702
0
                        reg1 = _mm_add_epi32(
3703
0
                            reg1,
3704
0
                            _mm_unpackhi_epi16(inputVal, _mm_setzero_si128()));
3705
0
                    }
3706
0
                    reg0 /= fast_d;
3707
0
                    reg1 /= fast_d;
3708
0
                    _mm_storeu_si128(reinterpret_cast<__m128i *>(pDest + iCol),
3709
0
                                     packus_epi32(reg0, reg1));
3710
0
                }
3711
0
                for (; iCol < nXSize; ++iCol)
3712
0
                {
3713
0
                    uint32_t acc = nSources / 2;
3714
0
                    for (int iSrc = 0; iSrc < nSources; ++iSrc)
3715
0
                    {
3716
0
                        acc += static_cast<const T * CPL_RESTRICT>(
3717
0
                            papoSources[iSrc])[iOffsetLine + iCol];
3718
0
                    }
3719
0
                    pDest[iCol] = static_cast<T>(acc / nSources);
3720
0
                }
3721
0
            }
3722
0
            return CE_None;
3723
0
        }
3724
3725
0
        if (!bHasNoData && eSrcType == GDT_Int16 && eBufType == GDT_Int16 &&
3726
0
            nPixelSpace == 2 &&
3727
0
            nSources <= std::numeric_limits<int32_t>::max() /
3728
0
                            std::numeric_limits<uint16_t>::max())
3729
0
        {
3730
0
            libdivide::divider<uint32_t> fast_d(nSources);
3731
0
            using T = int16_t;
3732
0
            const auto halfConstant = _mm_set1_epi32(nSources / 2);
3733
0
            const auto shift = _mm_set1_epi16(std::numeric_limits<T>::min());
3734
0
            constexpr int VALUES_PER_REG = 8;
3735
0
            for (int iLine = 0; iLine < nYSize; ++iLine)
3736
0
            {
3737
0
                T *CPL_RESTRICT pDest = reinterpret_cast<T *>(
3738
0
                    static_cast<GByte *>(pData) +
3739
0
                    static_cast<GSpacing>(nLineSpace) * iLine);
3740
0
                const size_t iOffsetLine = static_cast<size_t>(iLine) * nXSize;
3741
0
                int iCol = 0;
3742
0
                for (; iCol < nXSize - (VALUES_PER_REG - 1);
3743
0
                     iCol += VALUES_PER_REG)
3744
0
                {
3745
0
                    __m128i reg0 = halfConstant;
3746
0
                    __m128i reg1 = halfConstant;
3747
0
                    for (int iSrc = 0; iSrc < nSources; ++iSrc)
3748
0
                    {
3749
                        // Shift input values by 32768 to get unsigned values
3750
0
                        const __m128i inputVal = _mm_add_epi16(
3751
0
                            _mm_loadu_si128(reinterpret_cast<const __m128i *>(
3752
0
                                static_cast<const T * CPL_RESTRICT>(
3753
0
                                    papoSources[iSrc]) +
3754
0
                                iOffsetLine + iCol)),
3755
0
                            shift);
3756
0
                        reg0 = _mm_add_epi32(
3757
0
                            reg0,
3758
0
                            _mm_unpacklo_epi16(inputVal, _mm_setzero_si128()));
3759
0
                        reg1 = _mm_add_epi32(
3760
0
                            reg1,
3761
0
                            _mm_unpackhi_epi16(inputVal, _mm_setzero_si128()));
3762
0
                    }
3763
0
                    reg0 /= fast_d;
3764
0
                    reg1 /= fast_d;
3765
0
                    _mm_storeu_si128(
3766
0
                        reinterpret_cast<__m128i *>(pDest + iCol),
3767
0
                        _mm_add_epi16(packus_epi32(reg0, reg1), shift));
3768
0
                }
3769
0
                for (; iCol < nXSize; ++iCol)
3770
0
                {
3771
0
                    int32_t acc = (-std::numeric_limits<T>::min()) * nSources +
3772
0
                                  nSources / 2;
3773
0
                    for (int iSrc = 0; iSrc < nSources; ++iSrc)
3774
0
                    {
3775
0
                        acc += static_cast<const T * CPL_RESTRICT>(
3776
0
                            papoSources[iSrc])[iOffsetLine + iCol];
3777
0
                    }
3778
0
                    pDest[iCol] = static_cast<T>(acc / nSources +
3779
0
                                                 std::numeric_limits<T>::min());
3780
0
                }
3781
0
            }
3782
0
            return CE_None;
3783
0
        }
3784
0
    }
3785
0
#endif  // defined(USE_SSE2) && !defined(USE_NEON_OPTIMIZATIONS)
3786
3787
0
#if defined(USE_SSE2)
3788
    if constexpr (std::is_same_v<Kernel, MeanKernel>)
3789
0
    {
3790
0
        if (!bHasNoData && eSrcType == GDT_Float32 && eBufType == GDT_Float32 &&
3791
0
            nPixelSpace == 4 && nSources > 0)
3792
0
        {
3793
0
            OptimizedMeanFloatSSE2<float, SSEWrapperFloat>(
3794
0
                papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
3795
0
            return CE_None;
3796
0
        }
3797
3798
0
        if (!bHasNoData && eSrcType == GDT_Float64 && eBufType == GDT_Float64 &&
3799
0
            nPixelSpace == 8 && nSources > 0)
3800
0
        {
3801
0
            OptimizedMeanFloatSSE2<double, SSEWrapperDouble>(
3802
0
                papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
3803
0
            return CE_None;
3804
0
        }
3805
0
    }
3806
0
#endif  // USE_SSE2
3807
3808
    /* ---- Set pixels ---- */
3809
0
    size_t ii = 0;
3810
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
3811
0
    {
3812
0
        for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
3813
0
        {
3814
0
            oKernel.Reset();
3815
0
            bool bWriteNoData = false;
3816
3817
0
            for (int iSrc = 0; iSrc < nSources; ++iSrc)
3818
0
            {
3819
0
                const double dfVal = GetSrcVal(papoSources[iSrc], eSrcType, ii);
3820
3821
0
                if (bHasNoData && IsNoData(dfVal, dfNoData))
3822
0
                {
3823
0
                    if (bPropagateNoData)
3824
0
                    {
3825
0
                        bWriteNoData = true;
3826
0
                        break;
3827
0
                    }
3828
0
                }
3829
0
                else
3830
0
                {
3831
0
                    oKernel.ProcessPixel(dfVal);
3832
0
                }
3833
0
            }
3834
3835
0
            double dfPixVal{dfNoData};
3836
0
            if (!bWriteNoData && oKernel.HasValue())
3837
0
            {
3838
0
                dfPixVal = oKernel.GetValue();
3839
0
            }
3840
3841
0
            GDALCopyWords(&dfPixVal, GDT_Float64, 0,
3842
0
                          static_cast<GByte *>(pData) +
3843
0
                              static_cast<GSpacing>(nLineSpace) * iLine +
3844
0
                              iCol * nPixelSpace,
3845
0
                          eBufType, nPixelSpace, 1);
3846
0
        }
3847
0
    }
3848
3849
    /* ---- Return success ---- */
3850
0
    return CE_None;
3851
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*)
3852
3853
/************************************************************************/
3854
/*                     GDALRegisterDefaultPixelFunc()                   */
3855
/************************************************************************/
3856
3857
/**
3858
 * This adds a default set of pixel functions to the global list of
3859
 * available pixel functions for derived bands:
3860
 *
3861
 * - "real": extract real part from a single raster band (just a copy if the
3862
 *           input is non-complex)
3863
 * - "imag": extract imaginary part from a single raster band (0 for
3864
 *           non-complex)
3865
 * - "complex": make a complex band merging two bands used as real and
3866
 *              imag values
3867
 * - "polar": make a complex band using input bands for amplitude and
3868
 *            phase values (b1 * exp( j * b2 ))
3869
 * - "mod": extract module from a single raster band (real or complex)
3870
 * - "phase": extract phase from a single raster band [-PI,PI] (0 or PI for
3871
              non-complex)
3872
 * - "conj": computes the complex conjugate of a single raster band (just a
3873
 *           copy if the input is non-complex)
3874
 * - "sum": sum 2 or more raster bands
3875
 * - "diff": computes the difference between 2 raster bands (b1 - b2)
3876
 * - "mul": multiply 2 or more raster bands
3877
 * - "div": divide one raster band by another (b1 / b2).
3878
 * - "min": minimum value of 2 or more raster bands
3879
 * - "max": maximum value of 2 or more raster bands
3880
 * - "norm_diff": computes the normalized difference between two raster bands:
3881
 *                ``(b1 - b2)/(b1 + b2)``.
3882
 * - "cmul": multiply the first band for the complex conjugate of the second
3883
 * - "inv": inverse (1./x).
3884
 * - "intensity": computes the intensity Re(x*conj(x)) of a single raster band
3885
 *                (real or complex)
3886
 * - "sqrt": perform the square root of a single raster band (real only)
3887
 * - "log10": compute the logarithm (base 10) of the abs of a single raster
3888
 *            band (real or complex): log10( abs( x ) )
3889
 * - "dB": perform conversion to dB of the abs of a single raster
3890
 *         band (real or complex): 20. * log10( abs( x ) ).
3891
 *         Note: the optional fact parameter can be set to 10. to get the
3892
 *         alternative formula: 10. * log10( abs( x ) )
3893
 * - "exp": computes the exponential of each element in the input band ``x``
3894
 *          (of real values): ``e ^ x``.
3895
 *          The function also accepts two optional parameters: ``base`` and
3896
 ``fact``
3897
 *          that allow to compute the generalized formula: ``base ^ ( fact *
3898
 x)``.
3899
 *          Note: this function is the recommended one to perform conversion
3900
 *          form logarithmic scale (dB): `` 10. ^ (x / 20.)``, in this case
3901
 *          ``base = 10.`` and ``fact = 1./20``
3902
 * - "dB2amp": perform scale conversion from logarithmic to linear
3903
 *             (amplitude) (i.e. 10 ^ ( x / 20 ) ) of a single raster
3904
 *             band (real only).
3905
 *             Deprecated in GDAL v3.5. Please use the ``exp`` pixel function
3906
 with
3907
 *             ``base = 10.`` and ``fact = 0.05`` i.e. ``1./20``
3908
 * - "dB2pow": perform scale conversion from logarithmic to linear
3909
 *             (power) (i.e. 10 ^ ( x / 10 ) ) of a single raster
3910
 *             band (real only)
3911
 *             Deprecated in GDAL v3.5. Please use the ``exp`` pixel function
3912
 with
3913
 *             ``base = 10.`` and ``fact = 0.1`` i.e. ``1./10``
3914
 * - "pow": raise a single raster band to a constant power
3915
 * - "interpolate_linear": interpolate values between two raster bands
3916
 *                         using linear interpolation
3917
 * - "interpolate_exp": interpolate values between two raster bands using
3918
 *                      exponential interpolation
3919
 * - "scale": Apply the RasterBand metadata values of "offset" and "scale"
3920
 * - "reclassify": Reclassify values matching ranges in a table
3921
 * - "nan": Convert incoming NoData values to IEEE 754 nan
3922
 *
3923
 * @see GDALAddDerivedBandPixelFunc
3924
 *
3925
 * @return CE_None
3926
 */
3927
CPLErr GDALRegisterDefaultPixelFunc()
3928
0
{
3929
0
    GDALAddDerivedBandPixelFunc("real", RealPixelFunc);
3930
0
    GDALAddDerivedBandPixelFunc("imag", ImagPixelFunc);
3931
0
    GDALAddDerivedBandPixelFunc("complex", ComplexPixelFunc);
3932
0
    GDALAddDerivedBandPixelFuncWithArgs("polar", PolarPixelFunc,
3933
0
                                        pszPolarPixelFuncMetadata);
3934
0
    GDALAddDerivedBandPixelFunc("mod", ModulePixelFunc);
3935
0
    GDALAddDerivedBandPixelFunc("phase", PhasePixelFunc);
3936
0
    GDALAddDerivedBandPixelFunc("conj", ConjPixelFunc);
3937
0
    GDALAddDerivedBandPixelFuncWithArgs("sum", SumPixelFunc,
3938
0
                                        pszSumPixelFuncMetadata);
3939
0
    GDALAddDerivedBandPixelFuncWithArgs("diff", DiffPixelFunc,
3940
0
                                        pszDiffPixelFuncMetadata);
3941
0
    GDALAddDerivedBandPixelFuncWithArgs("mul", MulPixelFunc,
3942
0
                                        pszMulPixelFuncMetadata);
3943
0
    GDALAddDerivedBandPixelFuncWithArgs("div", DivPixelFunc,
3944
0
                                        pszDivPixelFuncMetadata);
3945
0
    GDALAddDerivedBandPixelFunc("cmul", CMulPixelFunc);
3946
0
    GDALAddDerivedBandPixelFuncWithArgs("inv", InvPixelFunc,
3947
0
                                        pszInvPixelFuncMetadata);
3948
0
    GDALAddDerivedBandPixelFunc("intensity", IntensityPixelFunc);
3949
0
    GDALAddDerivedBandPixelFuncWithArgs("sqrt", SqrtPixelFunc,
3950
0
                                        pszSqrtPixelFuncMetadata);
3951
0
    GDALAddDerivedBandPixelFuncWithArgs("log10", Log10PixelFunc,
3952
0
                                        pszLog10PixelFuncMetadata);
3953
0
    GDALAddDerivedBandPixelFuncWithArgs("dB", DBPixelFunc,
3954
0
                                        pszDBPixelFuncMetadata);
3955
0
    GDALAddDerivedBandPixelFuncWithArgs("exp", ExpPixelFunc,
3956
0
                                        pszExpPixelFuncMetadata);
3957
0
    GDALAddDerivedBandPixelFunc("dB2amp",
3958
0
                                dB2AmpPixelFunc);  // deprecated in v3.5
3959
0
    GDALAddDerivedBandPixelFunc("dB2pow",
3960
0
                                dB2PowPixelFunc);  // deprecated in v3.5
3961
0
    GDALAddDerivedBandPixelFuncWithArgs("pow", PowPixelFunc,
3962
0
                                        pszPowPixelFuncMetadata);
3963
0
    GDALAddDerivedBandPixelFuncWithArgs("interpolate_linear",
3964
0
                                        InterpolatePixelFunc<InterpolateLinear>,
3965
0
                                        pszInterpolatePixelFuncMetadata);
3966
0
    GDALAddDerivedBandPixelFuncWithArgs(
3967
0
        "interpolate_exp", InterpolatePixelFunc<InterpolateExponential>,
3968
0
        pszInterpolatePixelFuncMetadata);
3969
0
    GDALAddDerivedBandPixelFuncWithArgs("replace_nodata",
3970
0
                                        ReplaceNoDataPixelFunc,
3971
0
                                        pszReplaceNoDataPixelFuncMetadata);
3972
0
    GDALAddDerivedBandPixelFuncWithArgs("scale", ScalePixelFunc,
3973
0
                                        pszScalePixelFuncMetadata);
3974
0
    GDALAddDerivedBandPixelFuncWithArgs("norm_diff", NormDiffPixelFunc,
3975
0
                                        pszNormDiffPixelFuncMetadata);
3976
0
    GDALAddDerivedBandPixelFuncWithArgs("min", MinPixelFunc,
3977
0
                                        pszMinMaxFuncMetadataNodata);
3978
0
    GDALAddDerivedBandPixelFuncWithArgs("max", MaxPixelFunc,
3979
0
                                        pszMinMaxFuncMetadataNodata);
3980
0
    GDALAddDerivedBandPixelFuncWithArgs("expression", ExprPixelFunc,
3981
0
                                        pszExprPixelFuncMetadata);
3982
0
    GDALAddDerivedBandPixelFuncWithArgs("reclassify", ReclassifyPixelFunc,
3983
0
                                        pszReclassifyPixelFuncMetadata);
3984
0
    GDALAddDerivedBandPixelFuncWithArgs("mean", BasicPixelFunc<MeanKernel>,
3985
0
                                        pszBasicPixelFuncMetadata);
3986
0
    GDALAddDerivedBandPixelFuncWithArgs("geometric_mean",
3987
0
                                        BasicPixelFunc<GeoMeanKernel>,
3988
0
                                        pszBasicPixelFuncMetadata);
3989
0
    GDALAddDerivedBandPixelFuncWithArgs("harmonic_mean",
3990
0
                                        BasicPixelFunc<HarmonicMeanKernel>,
3991
0
                                        pszBasicPixelFuncMetadata);
3992
0
    GDALAddDerivedBandPixelFuncWithArgs("median", BasicPixelFunc<MedianKernel>,
3993
0
                                        pszBasicPixelFuncMetadata);
3994
0
    GDALAddDerivedBandPixelFuncWithArgs("mode", BasicPixelFunc<ModeKernel>,
3995
0
                                        pszBasicPixelFuncMetadata);
3996
0
    return CE_None;
3997
0
}