Coverage Report

Created: 2026-08-14 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opencv/3rdparty/openexr/IlmImf/dwaLookups.cpp
Line
Count
Source
1
///////////////////////////////////////////////////////////////////////////
2
//
3
// Copyright (c) 2009-2014 DreamWorks Animation LLC. 
4
//
5
// All rights reserved.
6
//
7
// Redistribution and use in source and binary forms, with or without
8
// modification, are permitted provided that the following conditions are
9
// met:
10
// *       Redistributions of source code must retain the above copyright
11
// notice, this list of conditions and the following disclaimer.
12
// *       Redistributions in binary form must reproduce the above
13
// copyright notice, this list of conditions and the following disclaimer
14
// in the documentation and/or other materials provided with the
15
// distribution.
16
// *       Neither the name of DreamWorks Animation nor the names of
17
// its contributors may be used to endorse or promote products derived
18
// from this software without specific prior written permission.
19
//
20
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
//
32
///////////////////////////////////////////////////////////////////////////
33
34
#define OPENEXR_BUILTIN_TABLES
35
36
//
37
// A program to generate various acceleration lookup tables 
38
// for Imf::DwaCompressor
39
//
40
41
#include <cstddef>
42
#include <stdio.h>
43
#include <stdlib.h>
44
#include <math.h>
45
#include <vector>
46
47
#include <OpenEXRConfig.h>
48
49
#ifndef OPENEXR_BUILTIN_TABLES
50
#ifdef OPENEXR_IMF_HAVE_SYSCONF_NPROCESSORS_ONLN
51
#include <unistd.h>
52
#endif
53
#endif // OPENEXR_BUILTIN_TABLES
54
55
#include <half.h>
56
#include <IlmThread.h>
57
#include <IlmThreadSemaphore.h>
58
#include <ImfIO.h>
59
#include <ImfXdr.h>
60
#include "ImfNamespace.h"
61
62
using namespace OPENEXR_IMF_NAMESPACE;
63
64
namespace {
65
66
#ifdef OPENEXR_BUILTIN_TABLES
67
static unsigned short dwaCompressorNoOp[0x10000] = {};
68
static unsigned short dwaCompressorToLinear[0x10000] = {};
69
static unsigned short dwaCompressorToNonlinear[0x10000] = {};
70
71
//static unsigned int closestDataOffset[0x10000] = {};
72
//static unsigned short closestData[0x80000] = {};
73
#else
74
75
    class LutHeaderWorker
76
    {
77
        public:
78
            class Runner : public ILMTHREAD_NAMESPACE::Thread
79
            {
80
                public:
81
                    Runner(LutHeaderWorker &worker, bool output):
82
                        ILMTHREAD_NAMESPACE::Thread(),
83
                        _worker(worker),
84
                        _output(output)
85
                    {
86
                        start();
87
                    }
88
89
                    virtual ~Runner()
90
                    {
91
                        _semaphore.wait();
92
                    }
93
94
                    virtual void run()
95
                    {
96
                        _semaphore.post();
97
                        _worker.run(_output);
98
                    }
99
100
                private:
101
                    LutHeaderWorker     &_worker;
102
                    bool                 _output;
103
                    ILMTHREAD_NAMESPACE::Semaphore _semaphore;
104
105
            }; // class LutHeaderWorker::Runner
106
107
108
            LutHeaderWorker(size_t startValue,
109
                            size_t endValue):
110
                _lastCandidateCount(0),
111
                _startValue(startValue),
112
                _endValue(endValue),
113
                _numElements(0),
114
                _offset(new size_t[numValues()]),
115
                _elements(new unsigned short[1024*1024*2])
116
            {
117
            }
118
119
            ~LutHeaderWorker()
120
            {
121
                delete[] _offset;
122
                delete[] _elements;
123
            }
124
125
            size_t lastCandidateCount() const
126
            {
127
                return _lastCandidateCount;
128
            }
129
130
            size_t numValues() const 
131
            {
132
                return _endValue - _startValue;
133
            }
134
135
            size_t numElements() const
136
            {
137
                return _numElements;
138
            }
139
140
            const size_t* offset() const
141
            {
142
                return _offset;
143
            }
144
145
            const unsigned short* elements() const
146
            {
147
                return _elements;
148
            }
149
150
            void run(bool outputProgress)
151
            {
152
                half candidate[16];
153
                int  candidateCount = 0;
154
155
                for (size_t input=_startValue; input<_endValue; ++input) {
156
157
                    if (outputProgress) {
158
#ifdef __GNUC__
159
                        if (input % 100 == 0) {
160
                            fprintf(stderr, 
161
                            " Building acceleration for DwaCompressor, %.2f %%      %c",
162
                                          100.*(float)input/(float)numValues(), 13);
163
                        }
164
#else
165
                        if (input % 1000 == 0) {
166
                            fprintf(stderr, 
167
                            " Building acceleration for DwaCompressor, %.2f %%\n",
168
                                          100.*(float)input/(float)numValues());
169
                        }
170
#endif
171
                    } 
172
173
                    
174
                    int  numSetBits = countSetBits(input);
175
                    half inputHalf, closestHalf;
176
177
                    inputHalf.setBits(input);
178
179
                    _offset[input - _startValue] = _numElements;
180
181
                    // Gather candidates
182
                    candidateCount = 0;
183
                    for (int targetNumSetBits=numSetBits-1; targetNumSetBits>=0;
184
                                                           --targetNumSetBits) {
185
                        bool valueFound = false;
186
187
                        for (int i=0; i<65536; ++i) {
188
                            if (countSetBits(i) != targetNumSetBits) continue;
189
190
                            if (!valueFound) {
191
                                closestHalf.setBits(i);
192
                                valueFound = true;
193
                            } else {
194
                                half tmpHalf;
195
196
                                tmpHalf.setBits(i);
197
198
                                if (fabs((float)inputHalf - (float)tmpHalf) < 
199
                                    fabs((float)inputHalf - (float)closestHalf)) {
200
                                    closestHalf = tmpHalf;
201
                                }
202
                            }
203
                        }
204
205
                        if (valueFound == false) {
206
                            fprintf(stderr, "bork bork bork!\n");
207
                        }       
208
209
                        candidate[candidateCount] = closestHalf;
210
                        candidateCount++;
211
                    }
212
213
                    // Sort candidates by increasing number of bits set
214
                    for (int i=0; i<candidateCount; ++i) {
215
                        for (int j=i+1; j<candidateCount; ++j) {
216
217
                            int   iCnt = countSetBits(candidate[i].bits());
218
                            int   jCnt = countSetBits(candidate[j].bits());
219
220
                            if (jCnt < iCnt) {
221
                                half tmp     = candidate[i];
222
                                candidate[i] = candidate[j];
223
                                candidate[j] = tmp;
224
                            }
225
                        }
226
                    }
227
228
                    // Copy candidates to the data buffer;
229
                    for (int i=0; i<candidateCount; ++i) {
230
                        _elements[_numElements] = candidate[i].bits();
231
                        _numElements++;
232
                    }
233
234
                    if (input == _endValue-1) {
235
                        _lastCandidateCount = candidateCount;
236
                    }
237
                }
238
            }
239
            
240
241
        private:
242
            size_t          _lastCandidateCount;
243
            size_t          _startValue;
244
            size_t          _endValue;
245
            size_t          _numElements;
246
            size_t         *_offset;
247
            unsigned short *_elements;
248
249
            //
250
            // Precomputing the bit count runs faster than using
251
            // the builtin instruction, at least in one case..
252
            //
253
            // Precomputing 8-bits is no slower than 16-bits,
254
            // and saves a fair bit of overhead..
255
            //
256
            int countSetBits(unsigned short src)
257
            {
258
                static const unsigned short numBitsSet[256] =
259
                {
260
                    0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
261
                    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
262
                    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
263
                    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
264
                    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
265
                    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
266
                    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
267
                    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
268
                    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
269
                    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
270
                    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
271
                    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
272
                    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
273
                    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
274
                    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
275
                    4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
276
                };
277
278
                return numBitsSet[src & 0xff] + numBitsSet[src >> 8];
279
            }
280
281
    }; // class LutHeaderWorker
282
283
#endif // OPENEXR_BUILTIN_TABLES
284
285
} // namespace
286
287
288
//
289
// Generate a no-op LUT, to cut down in conditional branches
290
//
291
static void
292
generateNoop()
293
0
{
294
#ifndef OPENEXR_BUILTIN_TABLES
295
    printf("const unsigned short dwaCompressorNoOp[] = \n");
296
    printf("{");
297
#endif // OPENEXR_BUILTIN_TABLES
298
0
    for (int i=0; i<65536; ++i) {
299
#ifndef OPENEXR_BUILTIN_TABLES
300
        if (i % 8 == 0) {
301
            printf("\n    ");
302
        }
303
#endif  // OPENEXR_BUILTIN_TABLES
304
0
        unsigned short dst;
305
0
        char *tmp = (char *)(&dst);
306
307
0
        unsigned short src = (unsigned short)i;
308
0
        Xdr::write <CharPtrIO> (tmp,  src);
309
#ifndef OPENEXR_BUILTIN_TABLES
310
        printf("0x%04x, ", dst);
311
#else
312
0
        dwaCompressorNoOp[i] = dst;
313
0
#endif // OPENEXR_BUILTIN_TABLES
314
0
    }
315
#ifndef OPENEXR_BUILTIN_TABLES
316
    printf("\n};\n");
317
#endif // OPENEXR_BUILTIN_TABLES
318
0
}
319
320
//
321
// Nonlinearly encode luminance. For values below 1.0, we want
322
// to use a gamma 2.2 function to match what is fairly common
323
// for storing output referred. However, > 1, gamma functions blow up,
324
// and log functions are much better behaved. We could use a log 
325
// function everywhere, but it tends to over-sample dark 
326
// regions and undersample the brighter regions, when 
327
// compared to the way real devices reproduce values.
328
//
329
// So, above 1, use a log function which is a smooth blend
330
// into the gamma function. 
331
//
332
//  Nonlinear(linear) = 
333
//
334
//    linear^(1./2.2)             / linear <= 1.0
335
//                               |
336
//    ln(linear)/ln(e^2.2) + 1    \ otherwise
337
//
338
//
339
// toNonlinear[] needs to take in XDR format half float values,
340
// and output NATIVE format float. 
341
//
342
// toLinear[] does the opposite - takes in NATIVE half and 
343
// outputs XDR half values.
344
//
345
346
static void
347
generateToLinear()
348
0
{
349
#ifndef OPENEXR_BUILTIN_TABLES
350
    unsigned short toLinear[65536];
351
#else
352
0
    unsigned short* toLinear = dwaCompressorToLinear;
353
0
#endif // OPENEXR_BUILTIN_TABLES
354
355
0
    toLinear[0] = 0;
356
357
0
    for (int i=1; i<65536; ++i) {
358
0
        half  h;
359
0
        float sign    = 1;
360
0
        float logBase = pow(2.7182818, 2.2);
361
362
        // map  NaN and inf to 0
363
0
        if ((i & 0x7c00) == 0x7c00) {
364
0
            toLinear[i]    = 0;
365
0
            continue;
366
0
        }
367
368
        //
369
        // _toLinear - assume i is NATIVE, but our output needs
370
        //             to get flipped to XDR
371
        //
372
0
        h.setBits(i);
373
0
        sign = 1;
374
0
        if ((float)h < 0) {
375
0
            sign = -1;
376
0
        } 
377
378
0
        if ( fabs( (float)h) <= 1.0 ) {
379
0
            h  = (half)(sign * pow((float)fabs((float)h), 2.2f));
380
0
        } else {
381
0
            h  = (half)(sign * pow(logBase, (float)(fabs((float)h) - 1.0)));
382
0
        }
383
384
0
        {
385
0
            char *tmp = (char *)(&toLinear[i]);
386
387
0
            Xdr::write <CharPtrIO> ( tmp,  h.bits());
388
0
        }
389
0
    }
390
#ifndef OPENEXR_BUILTIN_TABLES
391
    printf("const unsigned short dwaCompressorToLinear[] = \n");
392
    printf("{");
393
    for (int i=0; i<65536; ++i) {
394
        if (i % 8 == 0) {
395
            printf("\n    ");
396
        }
397
        printf("0x%04x, ", toLinear[i]);
398
    }
399
    printf("\n};\n");
400
#endif // OPENEXR_BUILTIN_TABLES
401
0
}
402
403
404
static void
405
generateToNonlinear()
406
0
{
407
#ifndef OPENEXR_BUILTIN_TABLES
408
    unsigned short toNonlinear[65536];
409
#else
410
0
    unsigned short* toNonlinear = dwaCompressorToNonlinear;
411
0
#endif // OPENEXR_BUILTIN_TABLES
412
413
0
    toNonlinear[0] = 0;
414
415
0
    for (int i=1; i<65536; ++i) {
416
0
        unsigned short usNative, usXdr;
417
0
        half  h;
418
0
        float sign    = 1;
419
0
        float logBase = pow(2.7182818, 2.2);
420
421
0
        usXdr           = i;
422
423
0
        {
424
0
            const char *tmp = (char *)(&usXdr);
425
426
0
            Xdr::read<CharPtrIO>(tmp, usNative);
427
0
        }
428
429
        // map  NaN and inf to 0
430
0
        if ((usNative & 0x7c00) == 0x7c00) {
431
0
            toNonlinear[i] = 0;
432
0
            continue;
433
0
        }
434
435
        //
436
        // toNonlinear - assume i is XDR
437
        //
438
0
        h.setBits(usNative);
439
0
        sign = 1;
440
0
        if ((float)h < 0) {
441
0
            sign = -1;
442
0
        } 
443
444
0
        if ( fabs( (float)h ) <= 1.0) {
445
0
            h = (half)(sign * pow(fabs((float)h), 1.f/2.2f));
446
0
        } else {
447
0
            h = (half)(sign * ( log(fabs((float)h)) / log(logBase) + 1.0) );
448
0
        }
449
0
        toNonlinear[i] = h.bits();
450
0
    }
451
#ifndef OPENEXR_BUILTIN_TABLES
452
    printf("const unsigned short dwaCompressorToNonlinear[] = \n");
453
    printf("{");
454
    for (int i=0; i<65536; ++i) {
455
        if (i % 8 == 0) {
456
            printf("\n    ");
457
        }
458
        printf("0x%04x, ", toNonlinear[i]);
459
    }
460
    printf("\n};\n");
461
#endif // OPENEXR_BUILTIN_TABLES
462
0
}
463
464
465
#ifndef OPENEXR_BUILTIN_TABLES
466
//
467
// Attempt to get available CPUs in a somewhat portable way. 
468
//
469
470
int
471
cpuCount()
472
{
473
    if (!ILMTHREAD_NAMESPACE::supportsThreads()) return 1;
474
475
    int cpuCount = 1;
476
477
#if defined (OPENEXR_IMF_HAVE_SYSCONF_NPROCESSORS_ONLN)
478
479
    cpuCount = sysconf(_SC_NPROCESSORS_ONLN);
480
481
#elif defined (_WIN32)
482
483
    SYSTEM_INFO sysinfo;
484
    GetSystemInfo( &sysinfo );
485
    cpuCount = sysinfo.dwNumberOfProcessors;
486
487
#endif
488
489
    if (cpuCount < 1) cpuCount = 1;
490
    return cpuCount;
491
}
492
493
//
494
// Generate acceleration luts for the quantization.
495
//
496
// For each possible input value, we want to find the closest numbers
497
// which have one fewer bits set than before. 
498
//
499
// This gives us num_bits(input)-1 values per input. If we alloc
500
// space for everything, that's like a 2MB table. We can do better
501
// by compressing all the values to be contigious and using offset
502
// pointers.
503
//
504
// After we've found the candidates with fewer bits set, sort them
505
// based on increasing numbers of bits set. This way, on quantize(),
506
// we can scan through the list and halt once we find the first
507
// candidate within the error range. For small values that can 
508
// be quantized to 0, 0 is the first value tested and the search
509
// can exit fairly quickly.
510
//
511
512
void
513
generateLutHeader()
514
{
515
    std::vector<LutHeaderWorker*> workers;
516
517
    size_t numWorkers     = cpuCount();
518
    size_t workerInterval = 65536 / numWorkers;
519
520
    for (size_t i=0; i<numWorkers; ++i) {
521
        if (i != numWorkers-1) {
522
            workers.push_back( new LutHeaderWorker( i   *workerInterval, 
523
                                                   (i+1)*workerInterval) );
524
        } else {
525
            workers.push_back( new LutHeaderWorker(i*workerInterval, 65536) );
526
        }
527
    }
528
529
    if (ILMTHREAD_NAMESPACE::supportsThreads()) {
530
        std::vector<LutHeaderWorker::Runner*> runners;
531
        for (size_t i=0; i<workers.size(); ++i) {
532
            runners.push_back( new LutHeaderWorker::Runner(*workers[i], (i==0)) );
533
        }
534
535
        for (size_t i=0; i<workers.size(); ++i) {
536
            delete runners[i];
537
        }
538
    } else {
539
        for (size_t i=0; i<workers.size(); ++i) {
540
            workers[i]->run(i == 0);
541
        }
542
    }
543
544
    printf("static unsigned int closestDataOffset[] = {\n");
545
    int offsetIdx  = 0;
546
    int offsetPrev = 0;
547
    for (size_t i=0; i<workers.size(); ++i) {
548
        for (size_t value=0; value<workers[i]->numValues(); ++value) {
549
            if (offsetIdx % 8 == 0) {
550
                printf("    ");
551
            }
552
            printf("%6lu, ", workers[i]->offset()[value] + offsetPrev);
553
            if (offsetIdx % 8 == 7) {
554
                printf("\n");
555
            }
556
            offsetIdx++;
557
        }
558
        offsetPrev += workers[i]->offset()[workers[i]->numValues()-1] + 
559
                      workers[i]->lastCandidateCount();
560
    }
561
    printf("};\n\n\n");
562
563
564
    printf("static unsigned short closestData[] = {\n");
565
    int elementIdx = 0;
566
    for (size_t i=0; i<workers.size(); ++i) {
567
        for (size_t element=0; element<workers[i]->numElements(); ++element) {
568
            if (elementIdx % 8 == 0) {
569
                printf("    ");
570
            }
571
            printf("%5d, ", workers[i]->elements()[element]);
572
            if (elementIdx % 8 == 7) {
573
                printf("\n");
574
            }
575
            elementIdx++;
576
        }    
577
    }
578
    printf("};\n\n\n");
579
580
    for (size_t i=0; i<workers.size(); ++i) {
581
        delete workers[i];
582
    }
583
}
584
585
586
int
587
main(int argc, char **argv)
588
{
589
    printf("#include <cstddef>\n");
590
    printf("\n\n\n");
591
592
    generateNoop();
593
594
    printf("\n\n\n");
595
596
    generateToLinear();
597
598
    printf("\n\n\n");
599
600
    generateToNonlinear();
601
602
    printf("\n\n\n");
603
604
    generateLutHeader();
605
606
    return 0;
607
}
608
#else // OPENEXR_BUILTIN_TABLES
609
610
#include "dwaLookups.h"
611
612
OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
613
614
static void init_dwa_()
615
0
{
616
0
    generateNoop();
617
0
    generateToLinear();
618
0
    generateToNonlinear();
619
    // N/A: generateLutHeader();
620
0
}
621
622
static inline void init_dwa()
623
0
{
624
0
    static bool initialized = false;
625
0
    if (!initialized)
626
0
    {
627
0
        init_dwa_();
628
0
        initialized = true;
629
0
    }
630
0
}
631
632
const unsigned short* get_dwaCompressorNoOp()
633
0
{
634
0
    init_dwa();
635
0
    return dwaCompressorNoOp;
636
0
}
637
const unsigned short* get_dwaCompressorToLinear()
638
0
{
639
0
    init_dwa();
640
0
    return dwaCompressorToLinear;
641
0
}
642
const unsigned short* get_dwaCompressorToNonlinear()
643
0
{
644
0
    init_dwa();
645
0
    return dwaCompressorToNonlinear;
646
0
}
647
648
OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
649
650
#endif // OPENEXR_BUILTIN_TABLES