1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                           License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
14 // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
15 // Copyright (C) 2015, Itseez Inc., all rights reserved.
16 // Third party copyrights are property of their respective owners.
17 //
18 // Redistribution and use in source and binary forms, with or without modification,
19 // are permitted provided that the following conditions are met:
20 //
21 //   * Redistribution's of source code must retain the above copyright notice,
22 //     this list of conditions and the following disclaimer.
23 //
24 //   * Redistribution's in binary form must reproduce the above copyright notice,
25 //     this list of conditions and the following disclaimer in the documentation
26 //     and/or other materials provided with the distribution.
27 //
28 //   * The name of the copyright holders may not be used to endorse or promote products
29 //     derived from this software without specific prior written permission.
30 //
31 // This software is provided by the copyright holders and contributors "as is" and
32 // any express or implied warranties, including, but not limited to, the implied
33 // warranties of merchantability and fitness for a particular purpose are disclaimed.
34 // In no event shall the Intel Corporation or contributors be liable for any direct,
35 // indirect, incidental, special, exemplary, or consequential damages
36 // (including, but not limited to, procurement of substitute goods or services;
37 // loss of use, data, or profits; or business interruption) however caused
38 // and on any theory of liability, whether in contract, strict liability,
39 // or tort (including negligence or otherwise) arising in any way out of
40 // the use of this software, even if advised of the possibility of such damage.
41 //
42 //M*/
43 
44 #include "precomp.hpp"
45 #include <iostream>
46 #include <ostream>
47 
48 #include <opencv2/core/utils/configuration.private.hpp>
49 #include <opencv2/core/utils/trace.private.hpp>
50 
51 #include <opencv2/core/utils/logger.hpp>
52 
53 #include <opencv2/core/utils/tls.hpp>
54 #include <opencv2/core/utils/instrumentation.hpp>
55 
56 #include <opencv2/core/utils/filesystem.private.hpp>
57 
58 namespace cv {
59 
_initSystem()60 static void _initSystem()
61 {
62 #ifdef __ANDROID__
63     // https://github.com/opencv/opencv/issues/14906
64     // "ios_base::Init" object is not a part of Android's "iostream" header (in case of clang toolchain, NDK 20).
65     // Ref1: https://en.cppreference.com/w/cpp/io/ios_base/Init
66     //       The header <iostream> behaves as if it defines (directly or indirectly) an instance of std::ios_base::Init with static storage duration
67     // Ref2: https://github.com/gcc-mirror/gcc/blob/gcc-8-branch/libstdc%2B%2B-v3/include/std/iostream#L73-L74
68     static std::ios_base::Init s_iostream_initializer;
69 #endif
70 }
71 
72 static Mutex* __initialization_mutex = NULL;
getInitializationMutex()73 Mutex& getInitializationMutex()
74 {
75     if (__initialization_mutex == NULL)
76     {
77         (void)_initSystem();
78         __initialization_mutex = new Mutex();
79     }
80     return *__initialization_mutex;
81 }
82 // force initialization (single-threaded environment)
83 Mutex* __initialization_mutex_initializer = &getInitializationMutex();
84 
85 static bool param_dumpErrors = utils::getConfigurationParameterBool("OPENCV_DUMP_ERRORS",
86 #if defined(_DEBUG) || defined(__ANDROID__)
87     true
88 #else
89     false
90 #endif
91 );
92 
allocSingletonBuffer(size_t size)93 void* allocSingletonBuffer(size_t size) { return fastMalloc(size); }
allocSingletonNewBuffer(size_t size)94 void* allocSingletonNewBuffer(size_t size) { return malloc(size); }
95 
96 
97 } // namespace cv
98 
99 #ifndef CV_ERROR_SET_TERMINATE_HANDLER  // build config option
100 # if defined(_WIN32)
101 #   define CV_ERROR_SET_TERMINATE_HANDLER 1
102 # endif
103 #endif
104 #if defined(CV_ERROR_SET_TERMINATE_HANDLER) && !CV_ERROR_SET_TERMINATE_HANDLER
105 # undef CV_ERROR_SET_TERMINATE_HANDLER
106 #endif
107 
108 #ifdef _MSC_VER
109 # if _MSC_VER >= 1700
110 #  pragma warning(disable:4447) // Disable warning 'main' signature found without threading model
111 # endif
112 #endif
113 
114 #ifdef CV_ERROR_SET_TERMINATE_HANDLER
115 #include <exception>      // std::set_terminate
116 #include <cstdlib>        // std::abort
117 #endif
118 
119 #if defined __ANDROID__ || defined __linux__ || defined __DragonFly__ || defined __OpenBSD__ || defined __HAIKU__ || defined __Fuchsia__
120 #  include <unistd.h>
121 #  include <fcntl.h>
122 #  include <elf.h>
123 #if defined __ANDROID__ || defined __linux__
124 #  include <linux/auxvec.h>
125 #endif
126 #endif
127 
128 #if defined __ANDROID__ && defined HAVE_CPUFEATURES
129 #  include <cpu-features.h>
130 #endif
131 
132 
133 #if (defined __ppc64__ || defined __PPC64__) && defined __linux__
134 # include "sys/auxv.h"
135 # ifndef AT_HWCAP2
136 #   define AT_HWCAP2 26
137 # endif
138 # ifndef PPC_FEATURE2_ARCH_2_07
139 #   define PPC_FEATURE2_ARCH_2_07 0x80000000
140 # endif
141 # ifndef PPC_FEATURE2_ARCH_3_00
142 #   define PPC_FEATURE2_ARCH_3_00 0x00800000
143 # endif
144 #endif
145 
146 #if defined _WIN32 || defined WINCE
147 #ifndef _WIN32_WINNT           // This is needed for the declaration of TryEnterCriticalSection in winbase.h with Visual Studio 2005 (and older?)
148   #define _WIN32_WINNT 0x0400  // http://msdn.microsoft.com/en-us/library/ms686857(VS.85).aspx
149 #endif
150 #include <windows.h>
151 #if (_WIN32_WINNT >= 0x0602)
152   #include <synchapi.h>
153 #endif
154 #if ((_WIN32_WINNT >= 0x0600) && !defined(CV_DISABLE_FLS)) || defined(CV_FORCE_FLS)
155   #include <fibersapi.h>
156   #define CV_USE_FLS
157 #endif
158 #undef small
159 #undef min
160 #undef max
161 #undef abs
162 #include <tchar.h>
163 
164 #ifdef WINRT
165 #include <wrl/client.h>
166 #ifndef __cplusplus_winrt
167 #include <windows.storage.h>
168 #pragma comment(lib, "runtimeobject.lib")
169 #endif // WINRT
170 
GetTempPathWinRT()171 std::wstring GetTempPathWinRT()
172 {
173 #ifdef __cplusplus_winrt
174     return std::wstring(Windows::Storage::ApplicationData::Current->TemporaryFolder->Path->Data());
175 #else
176     Microsoft::WRL::ComPtr<ABI::Windows::Storage::IApplicationDataStatics> appdataFactory;
177     Microsoft::WRL::ComPtr<ABI::Windows::Storage::IApplicationData> appdataRef;
178     Microsoft::WRL::ComPtr<ABI::Windows::Storage::IStorageFolder> storagefolderRef;
179     Microsoft::WRL::ComPtr<ABI::Windows::Storage::IStorageItem> storageitemRef;
180     HSTRING str;
181     HSTRING_HEADER hstrHead;
182     std::wstring wstr;
183     if (FAILED(WindowsCreateStringReference(RuntimeClass_Windows_Storage_ApplicationData,
184                                             (UINT32)wcslen(RuntimeClass_Windows_Storage_ApplicationData), &hstrHead, &str)))
185         return wstr;
186     if (FAILED(RoGetActivationFactory(str, IID_PPV_ARGS(appdataFactory.ReleaseAndGetAddressOf()))))
187         return wstr;
188     if (FAILED(appdataFactory->get_Current(appdataRef.ReleaseAndGetAddressOf())))
189         return wstr;
190     if (FAILED(appdataRef->get_TemporaryFolder(storagefolderRef.ReleaseAndGetAddressOf())))
191         return wstr;
192     if (FAILED(storagefolderRef.As(&storageitemRef)))
193         return wstr;
194     str = NULL;
195     if (FAILED(storageitemRef->get_Path(&str)))
196         return wstr;
197     wstr = WindowsGetStringRawBuffer(str, NULL);
198     WindowsDeleteString(str);
199     return wstr;
200 #endif
201 }
202 
GetTempFileNameWinRT(std::wstring prefix)203 std::wstring GetTempFileNameWinRT(std::wstring prefix)
204 {
205     wchar_t guidStr[40];
206     GUID g;
207     CoCreateGuid(&g);
208     wchar_t* mask = L"%08x_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x";
209     swprintf(&guidStr[0], sizeof(guidStr)/sizeof(wchar_t), mask,
210              g.Data1, g.Data2, g.Data3, UINT(g.Data4[0]), UINT(g.Data4[1]),
211              UINT(g.Data4[2]), UINT(g.Data4[3]), UINT(g.Data4[4]),
212              UINT(g.Data4[5]), UINT(g.Data4[6]), UINT(g.Data4[7]));
213 
214     return prefix.append(std::wstring(guidStr));
215 }
216 
217 #endif
218 #else
219 #include <pthread.h>
220 #include <sys/time.h>
221 #include <time.h>
222 
223 #if defined __MACH__ && defined __APPLE__
224 #include <mach/mach.h>
225 #include <mach/mach_time.h>
226 #endif
227 
228 #endif
229 
230 #ifdef _OPENMP
231 #include "omp.h"
232 #endif
233 
234 #if defined __linux__ || defined __APPLE__ || defined __EMSCRIPTEN__ || defined __DragonFly__ || defined __GLIBC__ || defined __HAIKU__
235 #include <unistd.h>
236 #include <stdio.h>
237 #include <sys/types.h>
238 #if defined __ANDROID__
239 #include <sys/sysconf.h>
240 #endif
241 #endif
242 
243 #ifdef __ANDROID__
244 # include <android/log.h>
245 #endif
246 
247 #ifdef DECLARE_CV_CPUID_X86
248 DECLARE_CV_CPUID_X86
249 #endif
250 #ifndef CV_CPUID_X86
251   #if defined _MSC_VER && (defined _M_IX86 || defined _M_X64)
252     #if _MSC_VER >= 1400  // MSVS 2005
253       #include <intrin.h>  // __cpuidex()
254       #define CV_CPUID_X86 __cpuidex
255     #else
256       #error "Required MSVS 2005+"
257     #endif
258   #elif defined __GNUC__ && (defined __i386__ || defined __x86_64__)
259     static void cv_cpuid(int* cpuid_data, int reg_eax, int reg_ecx)
260     {
261         int __eax = reg_eax, __ebx = 0, __ecx = reg_ecx, __edx = 0;
262 // tested with available compilers (-fPIC -O2 -m32/-m64): https://godbolt.org/
263 #if !defined(__PIC__) \
264     || defined(__x86_64__) || __GNUC__ >= 5 \
265     || defined(__clang__) || defined(__INTEL_COMPILER)
266         __asm__("cpuid\n\t"
267                 : "+a" (__eax), "=b" (__ebx), "+c" (__ecx), "=d" (__edx)
268         );
269 #elif defined(__i386__)  // ebx may be reserved as the PIC register
270         __asm__("xchg{l}\t{%%}ebx, %1\n\t"
271                 "cpuid\n\t"
272                 "xchg{l}\t{%%}ebx, %1\n\t"
273                 : "+a" (__eax), "=&r" (__ebx), "+c" (__ecx), "=d" (__edx)
274         );
275 #else
276 #error "Configuration error"
277 #endif
278         cpuid_data[0] = __eax; cpuid_data[1] = __ebx; cpuid_data[2] = __ecx; cpuid_data[3] = __edx;
279     }
280     #define CV_CPUID_X86 cv_cpuid
281   #endif
282 #endif
283 
284 
285 namespace cv
286 {
287 
Exception()288 Exception::Exception() { code = 0; line = 0; }
289 
Exception(int _code,const String & _err,const String & _func,const String & _file,int _line)290 Exception::Exception(int _code, const String& _err, const String& _func, const String& _file, int _line)
291 : code(_code), err(_err), func(_func), file(_file), line(_line)
292 {
293     formatMessage();
294 }
295 
~Exception()296 Exception::~Exception() throw() {}
297 
298 /*!
299  \return the error description and the context as a text string.
300  */
what() const301 const char* Exception::what() const throw() { return msg.c_str(); }
302 
formatMessage()303 void Exception::formatMessage()
304 {
305     size_t pos = err.find('\n');
306     bool multiline = pos != cv::String::npos;
307     if (multiline)
308     {
309         std::stringstream ss;
310         size_t prev_pos = 0;
311         while (pos != cv::String::npos)
312         {
313            ss << "> " << err.substr(prev_pos, pos - prev_pos) << std::endl;
314            prev_pos = pos + 1;
315            pos = err.find('\n', prev_pos);
316         }
317         ss << "> " << err.substr(prev_pos);
318         if (err[err.size() - 1] != '\n')
319             ss << std::endl;
320         err = ss.str();
321     }
322     if (func.size() > 0)
323     {
324         if (multiline)
325             msg = format("OpenCV(%s) %s:%d: error: (%d:%s) in function '%s'\n%s", CV_VERSION, file.c_str(), line, code, cvErrorStr(code), func.c_str(), err.c_str());
326         else
327             msg = format("OpenCV(%s) %s:%d: error: (%d:%s) %s in function '%s'\n", CV_VERSION, file.c_str(), line, code, cvErrorStr(code), err.c_str(), func.c_str());
328     }
329     else
330     {
331         msg = format("OpenCV(%s) %s:%d: error: (%d:%s) %s%s", CV_VERSION, file.c_str(), line, code, cvErrorStr(code), err.c_str(), multiline ? "" : "\n");
332     }
333 }
334 
335 static const char* g_hwFeatureNames[CV_HARDWARE_MAX_FEATURE] = { NULL };
336 
getHWFeatureName(int id)337 static const char* getHWFeatureName(int id)
338 {
339     return (id < CV_HARDWARE_MAX_FEATURE) ? g_hwFeatureNames[id] : NULL;
340 }
getHWFeatureNameSafe(int id)341 static const char* getHWFeatureNameSafe(int id)
342 {
343     const char* name = getHWFeatureName(id);
344     return name ? name : "Unknown feature";
345 }
346 
347 struct HWFeatures
348 {
349     enum { MAX_FEATURE = CV_HARDWARE_MAX_FEATURE };
350 
HWFeaturescv::HWFeatures351     HWFeatures(bool run_initialize = false)
352     {
353         if (run_initialize)
354             initialize();
355     }
356 
initializeNamescv::HWFeatures357     static void initializeNames()
358     {
359         for (int i = 0; i < CV_HARDWARE_MAX_FEATURE; i++)
360         {
361             g_hwFeatureNames[i] = 0;
362         }
363         g_hwFeatureNames[CPU_MMX] = "MMX";
364         g_hwFeatureNames[CPU_SSE] = "SSE";
365         g_hwFeatureNames[CPU_SSE2] = "SSE2";
366         g_hwFeatureNames[CPU_SSE3] = "SSE3";
367         g_hwFeatureNames[CPU_SSSE3] = "SSSE3";
368         g_hwFeatureNames[CPU_SSE4_1] = "SSE4.1";
369         g_hwFeatureNames[CPU_SSE4_2] = "SSE4.2";
370         g_hwFeatureNames[CPU_POPCNT] = "POPCNT";
371         g_hwFeatureNames[CPU_FP16] = "FP16";
372         g_hwFeatureNames[CPU_AVX] = "AVX";
373         g_hwFeatureNames[CPU_AVX2] = "AVX2";
374         g_hwFeatureNames[CPU_FMA3] = "FMA3";
375 
376         g_hwFeatureNames[CPU_AVX_512F] = "AVX512F";
377         g_hwFeatureNames[CPU_AVX_512BW] = "AVX512BW";
378         g_hwFeatureNames[CPU_AVX_512CD] = "AVX512CD";
379         g_hwFeatureNames[CPU_AVX_512DQ] = "AVX512DQ";
380         g_hwFeatureNames[CPU_AVX_512ER] = "AVX512ER";
381         g_hwFeatureNames[CPU_AVX_512IFMA] = "AVX512IFMA";
382         g_hwFeatureNames[CPU_AVX_512PF] = "AVX512PF";
383         g_hwFeatureNames[CPU_AVX_512VBMI] = "AVX512VBMI";
384         g_hwFeatureNames[CPU_AVX_512VL] = "AVX512VL";
385         g_hwFeatureNames[CPU_AVX_512VBMI2] = "AVX512VBMI2";
386         g_hwFeatureNames[CPU_AVX_512VNNI] = "AVX512VNNI";
387         g_hwFeatureNames[CPU_AVX_512BITALG] = "AVX512BITALG";
388         g_hwFeatureNames[CPU_AVX_512VPOPCNTDQ] = "AVX512VPOPCNTDQ";
389         g_hwFeatureNames[CPU_AVX_5124VNNIW] = "AVX5124VNNIW";
390         g_hwFeatureNames[CPU_AVX_5124FMAPS] = "AVX5124FMAPS";
391 
392         g_hwFeatureNames[CPU_NEON] = "NEON";
393 
394         g_hwFeatureNames[CPU_VSX] = "VSX";
395         g_hwFeatureNames[CPU_VSX3] = "VSX3";
396 
397         g_hwFeatureNames[CPU_MSA] = "CPU_MSA";
398         g_hwFeatureNames[CPU_RISCVV] = "RISCVV";
399 
400         g_hwFeatureNames[CPU_AVX512_COMMON] = "AVX512-COMMON";
401         g_hwFeatureNames[CPU_AVX512_SKX] = "AVX512-SKX";
402         g_hwFeatureNames[CPU_AVX512_KNL] = "AVX512-KNL";
403         g_hwFeatureNames[CPU_AVX512_KNM] = "AVX512-KNM";
404         g_hwFeatureNames[CPU_AVX512_CNL] = "AVX512-CNL";
405         g_hwFeatureNames[CPU_AVX512_CLX] = "AVX512-CLX";
406         g_hwFeatureNames[CPU_AVX512_ICL] = "AVX512-ICL";
407 
408         g_hwFeatureNames[CPU_RVV] = "RVV";
409     }
410 
initializecv::HWFeatures411     void initialize(void)
412     {
413 #ifndef NO_GETENV
414         if (getenv("OPENCV_DUMP_CONFIG"))
415         {
416             fprintf(stderr, "\nOpenCV build configuration is:\n%s\n",
417                 cv::getBuildInformation().c_str());
418         }
419 #endif
420 
421         initializeNames();
422 
423     #ifdef CV_CPUID_X86
424         int cpuid_data[4] = { 0, 0, 0, 0 };
425         int cpuid_data_ex[4] = { 0, 0, 0, 0 };
426 
427         CV_CPUID_X86(cpuid_data, 1, 0/*unused*/);
428 
429         int x86_family = (cpuid_data[0] >> 8) & 15;
430         if( x86_family >= 6 )
431         {
432             have[CV_CPU_MMX]    = (cpuid_data[3] & (1<<23)) != 0;
433             have[CV_CPU_SSE]    = (cpuid_data[3] & (1<<25)) != 0;
434             have[CV_CPU_SSE2]   = (cpuid_data[3] & (1<<26)) != 0;
435             have[CV_CPU_SSE3]   = (cpuid_data[2] & (1<<0)) != 0;
436             have[CV_CPU_SSSE3]  = (cpuid_data[2] & (1<<9)) != 0;
437             have[CV_CPU_FMA3]   = (cpuid_data[2] & (1<<12)) != 0;
438             have[CV_CPU_SSE4_1] = (cpuid_data[2] & (1<<19)) != 0;
439             have[CV_CPU_SSE4_2] = (cpuid_data[2] & (1<<20)) != 0;
440             have[CV_CPU_POPCNT] = (cpuid_data[2] & (1<<23)) != 0;
441             have[CV_CPU_AVX]    = (cpuid_data[2] & (1<<28)) != 0;
442             have[CV_CPU_FP16]   = (cpuid_data[2] & (1<<29)) != 0;
443 
444             // make the second call to the cpuid command in order to get
445             // information about extended features like AVX2
446             CV_CPUID_X86(cpuid_data_ex, 7, 0);
447 
448             have[CV_CPU_AVX2]   = (cpuid_data_ex[1] & (1<<5)) != 0;
449 
450             have[CV_CPU_AVX_512F]         = (cpuid_data_ex[1] & (1<<16)) != 0;
451             have[CV_CPU_AVX_512DQ]        = (cpuid_data_ex[1] & (1<<17)) != 0;
452             have[CV_CPU_AVX_512IFMA]      = (cpuid_data_ex[1] & (1<<21)) != 0;
453             have[CV_CPU_AVX_512PF]        = (cpuid_data_ex[1] & (1<<26)) != 0;
454             have[CV_CPU_AVX_512ER]        = (cpuid_data_ex[1] & (1<<27)) != 0;
455             have[CV_CPU_AVX_512CD]        = (cpuid_data_ex[1] & (1<<28)) != 0;
456             have[CV_CPU_AVX_512BW]        = (cpuid_data_ex[1] & (1<<30)) != 0;
457             have[CV_CPU_AVX_512VL]        = (cpuid_data_ex[1] & (1<<31)) != 0;
458             have[CV_CPU_AVX_512VBMI]      = (cpuid_data_ex[2] & (1<<1))  != 0;
459             have[CV_CPU_AVX_512VBMI2]     = (cpuid_data_ex[2] & (1<<6))  != 0;
460             have[CV_CPU_AVX_512VNNI]      = (cpuid_data_ex[2] & (1<<11)) != 0;
461             have[CV_CPU_AVX_512BITALG]    = (cpuid_data_ex[2] & (1<<12)) != 0;
462             have[CV_CPU_AVX_512VPOPCNTDQ] = (cpuid_data_ex[2] & (1<<14)) != 0;
463             have[CV_CPU_AVX_5124VNNIW]    = (cpuid_data_ex[3] & (1<<2))  != 0;
464             have[CV_CPU_AVX_5124FMAPS]    = (cpuid_data_ex[3] & (1<<3))  != 0;
465 
466             bool have_AVX_OS_support = true;
467             bool have_AVX512_OS_support = true;
468             if (!(cpuid_data[2] & (1<<27)))
469                 have_AVX_OS_support = false; // OS uses XSAVE_XRSTORE and CPU support AVX
470             else
471             {
472                 int xcr0 = 0;
473             #ifdef _XCR_XFEATURE_ENABLED_MASK // requires immintrin.h
474                 xcr0 = (int)_xgetbv(_XCR_XFEATURE_ENABLED_MASK);
475             #elif defined __GNUC__ && (defined __i386__ || defined __x86_64__)
476                 __asm__ ("xgetbv\n\t" : "=a" (xcr0) : "c" (0) : "%edx" );
477             #endif
478                 if ((xcr0 & 0x6) != 0x6)
479                     have_AVX_OS_support = false; // YMM registers
480                 if ((xcr0 & 0xe6) != 0xe6)
481                     have_AVX512_OS_support = false; // ZMM registers
482             }
483 
484             if (!have_AVX_OS_support)
485             {
486                 have[CV_CPU_AVX] = false;
487                 have[CV_CPU_FP16] = false;
488                 have[CV_CPU_AVX2] = false;
489                 have[CV_CPU_FMA3] = false;
490             }
491             if (!have_AVX_OS_support || !have_AVX512_OS_support)
492             {
493                 have[CV_CPU_AVX_512F] = false;
494                 have[CV_CPU_AVX_512BW] = false;
495                 have[CV_CPU_AVX_512CD] = false;
496                 have[CV_CPU_AVX_512DQ] = false;
497                 have[CV_CPU_AVX_512ER] = false;
498                 have[CV_CPU_AVX_512IFMA] = false;
499                 have[CV_CPU_AVX_512PF] = false;
500                 have[CV_CPU_AVX_512VBMI] = false;
501                 have[CV_CPU_AVX_512VL] = false;
502                 have[CV_CPU_AVX_512VBMI2] = false;
503                 have[CV_CPU_AVX_512VNNI] = false;
504                 have[CV_CPU_AVX_512BITALG] = false;
505                 have[CV_CPU_AVX_512VPOPCNTDQ] = false;
506                 have[CV_CPU_AVX_5124VNNIW] = false;
507                 have[CV_CPU_AVX_5124FMAPS] = false;
508             }
509 
510             have[CV_CPU_AVX512_COMMON] = have[CV_CPU_AVX_512F] && have[CV_CPU_AVX_512CD];
511             if (have[CV_CPU_AVX512_COMMON])
512             {
513                 have[CV_CPU_AVX512_KNL] = have[CV_CPU_AVX_512ER]  && have[CV_CPU_AVX_512PF];
514                 have[CV_CPU_AVX512_KNM] = have[CV_CPU_AVX512_KNL] && have[CV_CPU_AVX_5124FMAPS] &&
515                                           have[CV_CPU_AVX_5124VNNIW] && have[CV_CPU_AVX_512VPOPCNTDQ];
516                 have[CV_CPU_AVX512_SKX] = have[CV_CPU_AVX_512BW] && have[CV_CPU_AVX_512DQ] && have[CV_CPU_AVX_512VL];
517                 have[CV_CPU_AVX512_CNL] = have[CV_CPU_AVX512_SKX] && have[CV_CPU_AVX_512IFMA] && have[CV_CPU_AVX_512VBMI];
518                 have[CV_CPU_AVX512_CLX] = have[CV_CPU_AVX512_SKX] && have[CV_CPU_AVX_512VNNI];
519                 have[CV_CPU_AVX512_ICL] = have[CV_CPU_AVX512_SKX] &&
520                                           have[CV_CPU_AVX_512IFMA] && have[CV_CPU_AVX_512VBMI] &&
521                                           have[CV_CPU_AVX_512VNNI] &&
522                                           have[CV_CPU_AVX_512VBMI2] && have[CV_CPU_AVX_512BITALG] && have[CV_CPU_AVX_512VPOPCNTDQ];
523             }
524             else
525             {
526                 have[CV_CPU_AVX512_KNL] = false;
527                 have[CV_CPU_AVX512_KNM] = false;
528                 have[CV_CPU_AVX512_SKX] = false;
529                 have[CV_CPU_AVX512_CNL] = false;
530                 have[CV_CPU_AVX512_CLX] = false;
531                 have[CV_CPU_AVX512_ICL] = false;
532             }
533         }
534     #endif // CV_CPUID_X86
535 
536     #if defined __ANDROID__ || defined __linux__ || defined __DragonFly__
537     #ifdef __aarch64__
538         have[CV_CPU_NEON] = true;
539         have[CV_CPU_FP16] = true;
540     #elif defined __arm__ && defined __ANDROID__
541       #if defined HAVE_CPUFEATURES
542         CV_LOG_INFO(NULL, "calling android_getCpuFeatures() ...");
543         uint64_t features = android_getCpuFeatures();
544         CV_LOG_INFO(NULL, cv::format("calling android_getCpuFeatures() ... Done (%llx)", (long long)features));
545         have[CV_CPU_NEON] = (features & ANDROID_CPU_ARM_FEATURE_NEON) != 0;
546         have[CV_CPU_FP16] = (features & ANDROID_CPU_ARM_FEATURE_VFP_FP16) != 0;
547       #else
548         CV_LOG_INFO(NULL, "cpufeatures library is not available for CPU detection");
549         #if CV_NEON
550         CV_LOG_INFO(NULL, "- NEON instructions is enabled via build flags");
551         have[CV_CPU_NEON] = true;
552         #else
553         CV_LOG_INFO(NULL, "- NEON instructions is NOT enabled via build flags");
554         #endif
555         #if CV_FP16
556         CV_LOG_INFO(NULL, "- FP16 instructions is enabled via build flags");
557         have[CV_CPU_FP16] = true;
558         #else
559         CV_LOG_INFO(NULL, "- FP16 instructions is NOT enabled via build flags");
560         #endif
561       #endif
562     #elif defined __arm__ && !defined __DragonFly__
563         int cpufile = open("/proc/self/auxv", O_RDONLY);
564 
565         if (cpufile >= 0)
566         {
567             Elf32_auxv_t auxv;
568             const size_t size_auxv_t = sizeof(auxv);
569 
570             while ((size_t)read(cpufile, &auxv, size_auxv_t) == size_auxv_t)
571             {
572                 if (auxv.a_type == AT_HWCAP)
573                 {
574                     have[CV_CPU_NEON] = (auxv.a_un.a_val & 4096) != 0;
575                     have[CV_CPU_FP16] = (auxv.a_un.a_val & 2) != 0;
576                     break;
577                 }
578             }
579 
580             close(cpufile);
581         }
582     #endif
583     #elif (defined __clang__ || defined __APPLE__)
584     #if (defined __ARM_NEON__ || (defined __ARM_NEON && defined __aarch64__))
585         have[CV_CPU_NEON] = true;
586     #endif
587     #if (defined __ARM_FP  && (((__ARM_FP & 0x2) != 0) && defined __ARM_NEON__))
588         have[CV_CPU_FP16] = true;
589     #endif
590     #endif
591     #if defined _ARM_ && (defined(_WIN32_WCE) && _WIN32_WCE >= 0x800)
592         have[CV_CPU_NEON] = true;
593     #endif
594     #ifdef __riscv_vector
595         have[CV_CPU_RISCVV] = true;
596     #endif
597     #ifdef __mips_msa
598         have[CV_CPU_MSA] = true;
599     #endif
600 
601     #if (defined __ppc64__ || defined __PPC64__) && defined __linux__
602         unsigned int hwcap = getauxval(AT_HWCAP);
603         if (hwcap & PPC_FEATURE_HAS_VSX) {
604             hwcap = getauxval(AT_HWCAP2);
605             if (hwcap & PPC_FEATURE2_ARCH_3_00) {
606                 have[CV_CPU_VSX] = have[CV_CPU_VSX3] = true;
607             } else {
608                 have[CV_CPU_VSX] = (hwcap & PPC_FEATURE2_ARCH_2_07) != 0;
609             }
610         }
611     #else
612         // TODO: AIX, FreeBSD
613         #if CV_VSX || defined _ARCH_PWR8 || defined __POWER9_VECTOR__
614             have[CV_CPU_VSX] = true;
615         #endif
616         #if CV_VSX3 || defined __POWER9_VECTOR__
617             have[CV_CPU_VSX3] = true;
618         #endif
619     #endif
620 
621     #if defined __riscv && defined __riscv_vector
622         have[CV_CPU_RVV] = true;
623     #endif
624 
625         bool skip_baseline_check = false;
626 #ifndef NO_GETENV
627         if (getenv("OPENCV_SKIP_CPU_BASELINE_CHECK"))
628         {
629             skip_baseline_check = true;
630         }
631 #endif
632         int baseline_features[] = { CV_CPU_BASELINE_FEATURES };
633         if (!checkFeatures(baseline_features, sizeof(baseline_features) / sizeof(baseline_features[0]))
634             && !skip_baseline_check)
635         {
636             fprintf(stderr, "\n"
637                     "******************************************************************\n"
638                     "* FATAL ERROR:                                                   *\n"
639                     "* This OpenCV build doesn't support current CPU/HW configuration *\n"
640                     "*                                                                *\n"
641                     "* Use OPENCV_DUMP_CONFIG=1 environment variable for details      *\n"
642                     "******************************************************************\n");
643             fprintf(stderr, "\nRequired baseline features:\n");
644             checkFeatures(baseline_features, sizeof(baseline_features) / sizeof(baseline_features[0]), true);
645             CV_Error(cv::Error::StsAssert, "Missing support for required CPU baseline features. Check OpenCV build configuration and required CPU/HW setup.");
646         }
647 
648         readSettings(baseline_features, sizeof(baseline_features) / sizeof(baseline_features[0]));
649     }
650 
checkFeaturescv::HWFeatures651     bool checkFeatures(const int* features, int count, bool dump = false)
652     {
653         bool result = true;
654         for (int i = 0; i < count; i++)
655         {
656             int feature = features[i];
657             if (feature)
658             {
659                 if (have[feature])
660                 {
661                     if (dump) fprintf(stderr, "    ID=%3d (%s) - OK\n", feature, getHWFeatureNameSafe(feature));
662                 }
663                 else
664                 {
665                     result = false;
666                     if (dump) fprintf(stderr, "    ID=%3d (%s) - NOT AVAILABLE\n", feature, getHWFeatureNameSafe(feature));
667                 }
668             }
669         }
670         return result;
671     }
672 
isSymbolSeparatorcv::HWFeatures673     static inline bool isSymbolSeparator(char c)
674     {
675         return c == ',' || c == ';';
676     }
677 
readSettingscv::HWFeatures678     void readSettings(const int* baseline_features, int baseline_count)
679     {
680         bool dump = true;
681         const char* disabled_features =
682 #ifdef NO_GETENV
683                 NULL;
684 #else
685                 getenv("OPENCV_CPU_DISABLE");
686 #endif
687         if (disabled_features && disabled_features[0] != 0)
688         {
689             const char* start = disabled_features;
690             for (;;)
691             {
692                 while (start[0] != 0 && isSymbolSeparator(start[0]))
693                 {
694                     start++;
695                 }
696                 if (start[0] == 0)
697                     break;
698                 const char* end = start;
699                 while (end[0] != 0 && !isSymbolSeparator(end[0]))
700                 {
701                     end++;
702                 }
703                 if (end == start)
704                     continue;
705                 cv::String feature(start, end);
706                 start = end;
707 
708                 CV_Assert(feature.size() > 0);
709 
710                 bool found = false;
711                 for (int i = 0; i < CV_HARDWARE_MAX_FEATURE; i++)
712                 {
713                     if (!g_hwFeatureNames[i]) continue;
714                     size_t len = strlen(g_hwFeatureNames[i]);
715                     if (len != feature.size()) continue;
716                     if (feature.compare(g_hwFeatureNames[i]) == 0)
717                     {
718                         bool isBaseline = false;
719                         for (int k = 0; k < baseline_count; k++)
720                         {
721                             if (baseline_features[k] == i)
722                             {
723                                 isBaseline = true;
724                                 break;
725                             }
726                         }
727                         if (isBaseline)
728                         {
729                             if (dump) fprintf(stderr, "OPENCV: Trying to disable baseline CPU feature: '%s'."
730                                                       "This has very limited effect, because code optimizations for this feature are executed unconditionally "
731                                                       "in the most cases.\n", getHWFeatureNameSafe(i));
732                         }
733                         if (!have[i])
734                         {
735                             if (dump) fprintf(stderr, "OPENCV: Trying to disable unavailable CPU feature on the current platform: '%s'.\n",
736                                 getHWFeatureNameSafe(i));
737                         }
738                         have[i] = false;
739 
740                         found = true;
741                         break;
742                     }
743                 }
744                 if (!found)
745                 {
746                     if (dump) fprintf(stderr, "OPENCV: Trying to disable unknown CPU feature: '%s'.\n", feature.c_str());
747                 }
748             }
749         }
750     }
751 
752     bool have[MAX_FEATURE+1]{};
753 };
754 
755 static HWFeatures  featuresEnabled(true), featuresDisabled = HWFeatures(false);
756 static HWFeatures* currentFeatures = &featuresEnabled;
757 
checkHardwareSupport(int feature)758 bool checkHardwareSupport(int feature)
759 {
760     CV_DbgAssert( 0 <= feature && feature <= CV_HARDWARE_MAX_FEATURE );
761     return currentFeatures->have[feature];
762 }
763 
getHardwareFeatureName(int feature)764 String getHardwareFeatureName(int feature)
765 {
766     const char* name = getHWFeatureName(feature);
767     return name ? String(name) : String();
768 }
769 
getCPUFeaturesLine()770 std::string getCPUFeaturesLine()
771 {
772     const int features[] = { CV_CPU_BASELINE_FEATURES, CV_CPU_DISPATCH_FEATURES };
773     const int sz = sizeof(features) / sizeof(features[0]);
774     std::string result;
775     std::string prefix;
776     for (int i = 1; i < sz; ++i)
777     {
778         if (features[i] == 0)
779         {
780             prefix = "*";
781             continue;
782         }
783         if (i != 1) result.append(" ");
784         result.append(prefix);
785         result.append(getHWFeatureNameSafe(features[i]));
786         if (!checkHardwareSupport(features[i])) result.append("?");
787     }
788     return result;
789 }
790 
791 volatile bool useOptimizedFlag = true;
792 
setUseOptimized(bool flag)793 void setUseOptimized( bool flag )
794 {
795     useOptimizedFlag = flag;
796     currentFeatures = flag ? &featuresEnabled : &featuresDisabled;
797 
798     ipp::setUseIPP(flag);
799 #ifdef HAVE_OPENCL
800     ocl::setUseOpenCL(flag);
801 #endif
802 }
803 
useOptimized(void)804 bool useOptimized(void)
805 {
806     return useOptimizedFlag;
807 }
808 
getTickCount(void)809 int64 getTickCount(void)
810 {
811 #if defined _WIN32 || defined WINCE
812     LARGE_INTEGER counter;
813     QueryPerformanceCounter( &counter );
814     return (int64)counter.QuadPart;
815 #elif defined __linux || defined __linux__
816     struct timespec tp;
817     clock_gettime(CLOCK_MONOTONIC, &tp);
818     return (int64)tp.tv_sec*1000000000 + tp.tv_nsec;
819 #elif defined __MACH__ && defined __APPLE__
820     return (int64)mach_absolute_time();
821 #else
822     struct timeval tv;
823     gettimeofday(&tv, NULL);
824     return (int64)tv.tv_sec*1000000 + tv.tv_usec;
825 #endif
826 }
827 
getTickFrequency(void)828 double getTickFrequency(void)
829 {
830 #if defined _WIN32 || defined WINCE
831     LARGE_INTEGER freq;
832     QueryPerformanceFrequency(&freq);
833     return (double)freq.QuadPart;
834 #elif defined __linux || defined __linux__
835     return 1e9;
836 #elif defined __MACH__ && defined __APPLE__
837     static double freq = 0;
838     if( freq == 0 )
839     {
840         mach_timebase_info_data_t sTimebaseInfo;
841         mach_timebase_info(&sTimebaseInfo);
842         freq = sTimebaseInfo.denom*1e9/sTimebaseInfo.numer;
843     }
844     return freq;
845 #else
846     return 1e6;
847 #endif
848 }
849 
850 #if defined __GNUC__ && (defined __i386__ || defined __x86_64__ || defined __ppc__)
851 #if defined(__i386__)
852 
getCPUTickCount(void)853 int64 getCPUTickCount(void)
854 {
855     int64 x;
856     __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
857     return x;
858 }
859 #elif defined(__x86_64__)
860 
getCPUTickCount(void)861 int64 getCPUTickCount(void)
862 {
863     unsigned hi, lo;
864     __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
865     return (int64)lo | ((int64)hi << 32);
866 }
867 
868 #elif defined(__ppc__)
869 
getCPUTickCount(void)870 int64 getCPUTickCount(void)
871 {
872     unsigned upper, lower, tmp;
873     __asm__ volatile(
874                      "0:                  \n"
875                      "\tmftbu   %0           \n"
876                      "\tmftb    %1           \n"
877                      "\tmftbu   %2           \n"
878                      "\tcmpw    %2,%0        \n"
879                      "\tbne     0b         \n"
880                      : "=r"(upper),"=r"(lower),"=r"(tmp)
881                      );
882     return lower | ((int64)upper << 32);
883 }
884 
885 #else
886 
887 #error "RDTSC not defined"
888 
889 #endif
890 
891 #elif defined _MSC_VER && defined _WIN32 && defined _M_IX86
892 
getCPUTickCount(void)893 int64 getCPUTickCount(void)
894 {
895     __asm _emit 0x0f;
896     __asm _emit 0x31;
897 }
898 
899 #else
900 
901 //#ifdef HAVE_IPP
902 //int64 getCPUTickCount(void)
903 //{
904 //    return ippGetCpuClocks();
905 //}
906 //#else
getCPUTickCount(void)907 int64 getCPUTickCount(void)
908 {
909     return getTickCount();
910 }
911 //#endif
912 
913 #endif
914 
getBuildInformation()915 const String& getBuildInformation()
916 {
917     static String build_info =
918 #include "version_string.inc"
919     ;
920     return build_info;
921 }
922 
getVersionString()923 String getVersionString() { return String(CV_VERSION); }
924 
getVersionMajor()925 int getVersionMajor() { return CV_VERSION_MAJOR; }
926 
getVersionMinor()927 int getVersionMinor() { return CV_VERSION_MINOR; }
928 
getVersionRevision()929 int getVersionRevision() { return CV_VERSION_REVISION; }
930 
format(const char * fmt,...)931 String format( const char* fmt, ... )
932 {
933     AutoBuffer<char, 1024> buf;
934 
935     for ( ; ; )
936     {
937         va_list va;
938         va_start(va, fmt);
939         int bsize = static_cast<int>(buf.size());
940         int len = cv_vsnprintf(buf.data(), bsize, fmt, va);
941         va_end(va);
942 
943         CV_Assert(len >= 0 && "Check format string for errors");
944         if (len >= bsize)
945         {
946             buf.resize(len + 1);
947             continue;
948         }
949         buf[bsize - 1] = 0;
950         return String(buf.data(), len);
951     }
952 }
953 
tempfile(const char * suffix)954 String tempfile( const char* suffix )
955 {
956 #if OPENCV_HAVE_FILESYSTEM_SUPPORT
957     String fname;
958 #ifndef NO_GETENV
959     const char *temp_dir = getenv("OPENCV_TEMP_PATH");
960 #endif
961 
962 #if defined _WIN32
963 #ifdef WINRT
964     RoInitialize(RO_INIT_MULTITHREADED);
965     std::wstring temp_dir = GetTempPathWinRT();
966 
967     std::wstring temp_file = GetTempFileNameWinRT(L"ocv");
968     if (temp_file.empty())
969         return String();
970 
971     temp_file = temp_dir.append(std::wstring(L"\\")).append(temp_file);
972     DeleteFileW(temp_file.c_str());
973 
974     char aname[MAX_PATH];
975     size_t copied = wcstombs(aname, temp_file.c_str(), MAX_PATH);
976     CV_Assert((copied != MAX_PATH) && (copied != (size_t)-1));
977     fname = String(aname);
978     RoUninitialize();
979 #elif defined(_WIN32_WCE)
980     const auto kMaxPathSize = MAX_PATH+1;
981     wchar_t temp_dir[kMaxPathSize] = {0};
982     wchar_t temp_file[kMaxPathSize] = {0};
983 
984     ::GetTempPathW(kMaxPathSize, temp_dir);
985 
986     if(0 != ::GetTempFileNameW(temp_dir, L"ocv", 0, temp_file)) {
987         DeleteFileW(temp_file);
988         char aname[MAX_PATH];
989         size_t copied = wcstombs(aname, temp_file, MAX_PATH);
990         CV_Assert((copied != MAX_PATH) && (copied != (size_t)-1));
991         fname = String(aname);
992     }
993 #else
994     char temp_dir2[MAX_PATH] = { 0 };
995     char temp_file[MAX_PATH] = { 0 };
996 
997     if (temp_dir == 0 || temp_dir[0] == 0)
998     {
999         ::GetTempPathA(sizeof(temp_dir2), temp_dir2);
1000         temp_dir = temp_dir2;
1001     }
1002     if(0 == ::GetTempFileNameA(temp_dir, "ocv", 0, temp_file))
1003         return String();
1004 
1005     DeleteFileA(temp_file);
1006 
1007     fname = temp_file;
1008 #endif
1009 # else
1010 #  ifdef __ANDROID__
1011     //char defaultTemplate[] = "/mnt/sdcard/__opencv_temp.XXXXXX";
1012     char defaultTemplate[] = "/data/local/tmp/__opencv_temp.XXXXXX";
1013 #  else
1014     char defaultTemplate[] = "/tmp/__opencv_temp.XXXXXX";
1015 #  endif
1016 
1017     if (temp_dir == 0 || temp_dir[0] == 0)
1018         fname = defaultTemplate;
1019     else
1020     {
1021         fname = temp_dir;
1022         char ech = fname[fname.size() - 1];
1023         if(ech != '/' && ech != '\\')
1024             fname = fname + "/";
1025         fname = fname + "__opencv_temp.XXXXXX";
1026     }
1027 
1028     const int fd = mkstemp((char*)fname.c_str());
1029     if (fd == -1) return String();
1030 
1031     close(fd);
1032     remove(fname.c_str());
1033 # endif
1034 
1035     if (suffix)
1036     {
1037         if (suffix[0] != '.')
1038             return fname + "." + suffix;
1039         else
1040             return fname + suffix;
1041     }
1042     return fname;
1043 #else // OPENCV_HAVE_FILESYSTEM_SUPPORT
1044     CV_UNUSED(suffix);
1045     CV_Error(Error::StsNotImplemented, "File system support is disabled in this OpenCV build!");
1046 #endif // OPENCV_HAVE_FILESYSTEM_SUPPORT
1047 }
1048 
1049 static ErrorCallback customErrorCallback = 0;
1050 static void* customErrorCallbackData = 0;
1051 static bool breakOnError = false;
1052 
setBreakOnError(bool value)1053 bool setBreakOnError(bool value)
1054 {
1055     bool prevVal = breakOnError;
1056     breakOnError = value;
1057     return prevVal;
1058 }
1059 
cv_snprintf(char * buf,int len,const char * fmt,...)1060 int cv_snprintf(char* buf, int len, const char* fmt, ...)
1061 {
1062     va_list va;
1063     va_start(va, fmt);
1064     int res = cv_vsnprintf(buf, len, fmt, va);
1065     va_end(va);
1066     return res;
1067 }
1068 
cv_vsnprintf(char * buf,int len,const char * fmt,va_list args)1069 int cv_vsnprintf(char* buf, int len, const char* fmt, va_list args)
1070 {
1071 #if defined _MSC_VER
1072     if (len <= 0) return len == 0 ? 1024 : -1;
1073     int res = _vsnprintf_s(buf, len, _TRUNCATE, fmt, args);
1074     // ensure null terminating on VS
1075     if (res >= 0 && res < len)
1076     {
1077         buf[res] = 0;
1078         return res;
1079     }
1080     else
1081     {
1082         buf[len - 1] = 0; // truncate happened
1083         return res >= len ? res : (len * 2);
1084     }
1085 #else
1086     return vsnprintf(buf, len, fmt, args);
1087 #endif
1088 }
1089 
dumpException(const Exception & exc)1090 static void dumpException(const Exception& exc)
1091 {
1092     const char* errorStr = cvErrorStr(exc.code);
1093     char buf[1 << 12];
1094 
1095     cv_snprintf(buf, sizeof(buf),
1096         "OpenCV(%s) Error: %s (%s) in %s, file %s, line %d",
1097         CV_VERSION,
1098         errorStr, exc.err.c_str(), exc.func.size() > 0 ?
1099         exc.func.c_str() : "unknown function", exc.file.c_str(), exc.line);
1100 #ifdef __ANDROID__
1101     __android_log_print(ANDROID_LOG_ERROR, "cv::error()", "%s", buf);
1102 #else
1103     fflush(stdout); fflush(stderr);
1104     fprintf(stderr, "%s\n", buf);
1105     fflush(stderr);
1106 #endif
1107 }
1108 
1109 #ifdef CV_ERROR_SET_TERMINATE_HANDLER
1110 static bool cv_terminate_handler_installed = false;
1111 static std::terminate_handler cv_old_terminate_handler;
1112 static cv::Exception cv_terminate_handler_exception;
1113 static bool param_setupTerminateHandler = utils::getConfigurationParameterBool("OPENCV_SETUP_TERMINATE_HANDLER", true);
cv_terminate_handler()1114 static void cv_terminate_handler() {
1115     std::cerr << "OpenCV: terminate handler is called! The last OpenCV error is:\n";
1116     dumpException(cv_terminate_handler_exception);
1117     if (false /*cv_old_terminate_handler*/)  // buggy behavior is observed with doubled "abort/retry/ignore" windows
1118         cv_old_terminate_handler();
1119     abort();
1120 }
1121 
1122 #endif
1123 
1124 #ifdef __GNUC__
1125 # if defined __clang__ || defined __APPLE__
1126 #   pragma GCC diagnostic push
1127 #   pragma GCC diagnostic ignored "-Winvalid-noreturn"
1128 # endif
1129 #endif
1130 
error(const Exception & exc)1131 void error( const Exception& exc )
1132 {
1133 #ifdef CV_ERROR_SET_TERMINATE_HANDLER
1134     {
1135         cv::AutoLock lock(getInitializationMutex());
1136         if (!cv_terminate_handler_installed)
1137         {
1138             if (param_setupTerminateHandler)
1139                 cv_old_terminate_handler = std::set_terminate(cv_terminate_handler);
1140             cv_terminate_handler_installed = true;
1141         }
1142         cv_terminate_handler_exception = exc;
1143     }
1144 #endif
1145 
1146     if (customErrorCallback != 0)
1147         customErrorCallback(exc.code, exc.func.c_str(), exc.err.c_str(),
1148                             exc.file.c_str(), exc.line, customErrorCallbackData);
1149     else if (param_dumpErrors)
1150     {
1151         dumpException(exc);
1152     }
1153 
1154     if(breakOnError)
1155     {
1156         static volatile int* p = 0;
1157         *p = 0;
1158     }
1159 
1160     throw exc;
1161 #ifdef __GNUC__
1162 # if !defined __clang__ && !defined __APPLE__
1163     // this suppresses this warning: "noreturn" function does return [enabled by default]
1164     __builtin_trap();
1165     // or use infinite loop: for (;;) {}
1166 # endif
1167 #endif
1168 }
1169 
error(int _code,const String & _err,const char * _func,const char * _file,int _line)1170 void error(int _code, const String& _err, const char* _func, const char* _file, int _line)
1171 {
1172     error(cv::Exception(_code, _err, _func, _file, _line));
1173 #ifdef __GNUC__
1174 # if !defined __clang__ && !defined __APPLE__
1175     // this suppresses this warning: "noreturn" function does return [enabled by default]
1176     __builtin_trap();
1177     // or use infinite loop: for (;;) {}
1178 # endif
1179 #endif
1180 }
1181 
1182 #ifdef __GNUC__
1183 # if defined __clang__ || defined __APPLE__
1184 #   pragma GCC diagnostic pop
1185 # endif
1186 #endif
1187 
1188 
1189 ErrorCallback
redirectError(ErrorCallback errCallback,void * userdata,void ** prevUserdata)1190 redirectError( ErrorCallback errCallback, void* userdata, void** prevUserdata)
1191 {
1192     if( prevUserdata )
1193         *prevUserdata = customErrorCallbackData;
1194 
1195     ErrorCallback prevCallback = customErrorCallback;
1196 
1197     customErrorCallback     = errCallback;
1198     customErrorCallbackData = userdata;
1199 
1200     return prevCallback;
1201 }
1202 
1203 }
1204 
cvCheckHardwareSupport(int feature)1205 CV_IMPL int cvCheckHardwareSupport(int feature)
1206 {
1207     CV_DbgAssert( 0 <= feature && feature <= CV_HARDWARE_MAX_FEATURE );
1208     return cv::currentFeatures->have[feature];
1209 }
1210 
cvUseOptimized(int flag)1211 CV_IMPL int cvUseOptimized( int flag )
1212 {
1213     int prevMode = cv::useOptimizedFlag;
1214     cv::setUseOptimized( flag != 0 );
1215     return prevMode;
1216 }
1217 
cvGetTickCount(void)1218 CV_IMPL int64  cvGetTickCount(void)
1219 {
1220     return cv::getTickCount();
1221 }
1222 
cvGetTickFrequency(void)1223 CV_IMPL double cvGetTickFrequency(void)
1224 {
1225     return cv::getTickFrequency()*1e-6;
1226 }
1227 
1228 CV_IMPL CvErrorCallback
cvRedirectError(CvErrorCallback errCallback,void * userdata,void ** prevUserdata)1229 cvRedirectError( CvErrorCallback errCallback, void* userdata, void** prevUserdata)
1230 {
1231     return cv::redirectError(errCallback, userdata, prevUserdata);
1232 }
1233 
cvNulDevReport(int,const char *,const char *,const char *,int,void *)1234 CV_IMPL int cvNulDevReport( int, const char*, const char*,
1235                             const char*, int, void* )
1236 {
1237     return 0;
1238 }
1239 
cvStdErrReport(int,const char *,const char *,const char *,int,void *)1240 CV_IMPL int cvStdErrReport( int, const char*, const char*,
1241                             const char*, int, void* )
1242 {
1243     return 0;
1244 }
1245 
cvGuiBoxReport(int,const char *,const char *,const char *,int,void *)1246 CV_IMPL int cvGuiBoxReport( int, const char*, const char*,
1247                             const char*, int, void* )
1248 {
1249     return 0;
1250 }
1251 
cvGetErrInfo(const char **,const char **,const char **,int *)1252 CV_IMPL int cvGetErrInfo( const char**, const char**, const char**, int* )
1253 {
1254     return 0;
1255 }
1256 
1257 
cvErrorStr(int status)1258 CV_IMPL const char* cvErrorStr( int status )
1259 {
1260     static char buf[256];
1261 
1262     switch (status)
1263     {
1264     case CV_StsOk :                  return "No Error";
1265     case CV_StsBackTrace :           return "Backtrace";
1266     case CV_StsError :               return "Unspecified error";
1267     case CV_StsInternal :            return "Internal error";
1268     case CV_StsNoMem :               return "Insufficient memory";
1269     case CV_StsBadArg :              return "Bad argument";
1270     case CV_StsNoConv :              return "Iterations do not converge";
1271     case CV_StsAutoTrace :           return "Autotrace call";
1272     case CV_StsBadSize :             return "Incorrect size of input array";
1273     case CV_StsNullPtr :             return "Null pointer";
1274     case CV_StsDivByZero :           return "Division by zero occurred";
1275     case CV_BadStep :                return "Image step is wrong";
1276     case CV_StsInplaceNotSupported : return "Inplace operation is not supported";
1277     case CV_StsObjectNotFound :      return "Requested object was not found";
1278     case CV_BadDepth :               return "Input image depth is not supported by function";
1279     case CV_StsUnmatchedFormats :    return "Formats of input arguments do not match";
1280     case CV_StsUnmatchedSizes :      return "Sizes of input arguments do not match";
1281     case CV_StsOutOfRange :          return "One of the arguments\' values is out of range";
1282     case CV_StsUnsupportedFormat :   return "Unsupported format or combination of formats";
1283     case CV_BadCOI :                 return "Input COI is not supported";
1284     case CV_BadNumChannels :         return "Bad number of channels";
1285     case CV_StsBadFlag :             return "Bad flag (parameter or structure field)";
1286     case CV_StsBadPoint :            return "Bad parameter of type CvPoint";
1287     case CV_StsBadMask :             return "Bad type of mask argument";
1288     case CV_StsParseError :          return "Parsing error";
1289     case CV_StsNotImplemented :      return "The function/feature is not implemented";
1290     case CV_StsBadMemBlock :         return "Memory block has been corrupted";
1291     case CV_StsAssert :              return "Assertion failed";
1292     case CV_GpuNotSupported :        return "No CUDA support";
1293     case CV_GpuApiCallError :        return "Gpu API call";
1294     case CV_OpenGlNotSupported :     return "No OpenGL support";
1295     case CV_OpenGlApiCallError :     return "OpenGL API call";
1296     };
1297 
1298     sprintf(buf, "Unknown %s code %d", status >= 0 ? "status":"error", status);
1299     return buf;
1300 }
1301 
cvGetErrMode(void)1302 CV_IMPL int cvGetErrMode(void)
1303 {
1304     return 0;
1305 }
1306 
cvSetErrMode(int)1307 CV_IMPL int cvSetErrMode(int)
1308 {
1309     return 0;
1310 }
1311 
cvGetErrStatus(void)1312 CV_IMPL int cvGetErrStatus(void)
1313 {
1314     return 0;
1315 }
1316 
cvSetErrStatus(int)1317 CV_IMPL void cvSetErrStatus(int)
1318 {
1319 }
1320 
1321 
cvError(int code,const char * func_name,const char * err_msg,const char * file_name,int line)1322 CV_IMPL void cvError( int code, const char* func_name,
1323                       const char* err_msg,
1324                       const char* file_name, int line )
1325 {
1326     cv::error(cv::Exception(code, err_msg, func_name, file_name, line));
1327 }
1328 
1329 /* function, which converts int to int */
1330 CV_IMPL int
cvErrorFromIppStatus(int status)1331 cvErrorFromIppStatus( int status )
1332 {
1333     switch (status)
1334     {
1335     case CV_BADSIZE_ERR:               return CV_StsBadSize;
1336     case CV_BADMEMBLOCK_ERR:           return CV_StsBadMemBlock;
1337     case CV_NULLPTR_ERR:               return CV_StsNullPtr;
1338     case CV_DIV_BY_ZERO_ERR:           return CV_StsDivByZero;
1339     case CV_BADSTEP_ERR:               return CV_BadStep;
1340     case CV_OUTOFMEM_ERR:              return CV_StsNoMem;
1341     case CV_BADARG_ERR:                return CV_StsBadArg;
1342     case CV_NOTDEFINED_ERR:            return CV_StsError;
1343     case CV_INPLACE_NOT_SUPPORTED_ERR: return CV_StsInplaceNotSupported;
1344     case CV_NOTFOUND_ERR:              return CV_StsObjectNotFound;
1345     case CV_BADCONVERGENCE_ERR:        return CV_StsNoConv;
1346     case CV_BADDEPTH_ERR:              return CV_BadDepth;
1347     case CV_UNMATCHED_FORMATS_ERR:     return CV_StsUnmatchedFormats;
1348     case CV_UNSUPPORTED_COI_ERR:       return CV_BadCOI;
1349     case CV_UNSUPPORTED_CHANNELS_ERR:  return CV_BadNumChannels;
1350     case CV_BADFLAG_ERR:               return CV_StsBadFlag;
1351     case CV_BADRANGE_ERR:              return CV_StsBadArg;
1352     case CV_BADCOEF_ERR:               return CV_StsBadArg;
1353     case CV_BADFACTOR_ERR:             return CV_StsBadArg;
1354     case CV_BADPOINT_ERR:              return CV_StsBadPoint;
1355 
1356     default:
1357       return CV_StsError;
1358     }
1359 }
1360 
1361 namespace cv {
1362 bool __termination = false;
1363 
1364 
1365 //////////////////////////////// thread-local storage ////////////////////////////////
1366 
1367 namespace details {
1368 
1369 #ifdef _WIN32
1370 #ifdef _MSC_VER
1371 #pragma warning(disable:4505) // unreferenced local function has been removed
1372 #endif
1373 #ifndef TLS_OUT_OF_INDEXES
1374 #define TLS_OUT_OF_INDEXES ((DWORD)0xFFFFFFFF)
1375 #endif
1376 #endif
1377 
1378 template <class T>
1379 class DisposedSingletonMark
1380 {
1381 private:
1382     static bool mark;
1383 protected:
DisposedSingletonMark()1384     DisposedSingletonMark() {}
~DisposedSingletonMark()1385     ~DisposedSingletonMark()
1386     {
1387         mark = true;
1388     }
1389 public:
isDisposed()1390     static bool isDisposed() { return mark; }
1391 };
1392 
1393 // TLS platform abstraction layer
1394 class TlsAbstraction : public DisposedSingletonMark<TlsAbstraction>
1395 {
1396 public:
1397     TlsAbstraction();
1398     ~TlsAbstraction();
getData() const1399     void* getData() const
1400     {
1401         if (isDisposed())  // guard: static initialization order fiasco
1402             return NULL;
1403         return getData_();
1404     }
setData(void * pData)1405     void setData(void *pData)
1406     {
1407         if (isDisposed())  // guard: static initialization order fiasco
1408             return;
1409         return setData_(pData);
1410     }
1411 
1412 private:
1413     void* getData_() const;
1414     void setData_(void *pData);
1415 
1416 #ifdef _WIN32
1417 #ifndef WINRT
1418     DWORD tlsKey;
1419 #endif
1420 #else // _WIN32
1421     pthread_key_t  tlsKey;
1422 #endif
1423 };
1424 
1425 template<> bool DisposedSingletonMark<TlsAbstraction>::mark = false;
1426 
getTlsAbstraction_()1427 static TlsAbstraction& getTlsAbstraction_()
1428 {
1429     static TlsAbstraction g_tls;  // disposed in atexit() handlers (required for unregistering our callbacks)
1430     return g_tls;
1431 }
getTlsAbstraction()1432 static TlsAbstraction* getTlsAbstraction()
1433 {
1434     static TlsAbstraction* instance = &getTlsAbstraction_();
1435     return DisposedSingletonMark<TlsAbstraction>::isDisposed() ? NULL : instance;
1436 }
1437 
1438 
1439 #ifdef _WIN32
1440 #ifdef WINRT
1441 static __declspec( thread ) void* tlsData = NULL; // using C++11 thread attribute for local thread data
TlsAbstraction()1442 TlsAbstraction::TlsAbstraction() {}
~TlsAbstraction()1443 TlsAbstraction::~TlsAbstraction()
1444 {
1445     cv::__termination = true;  // DllMain is missing in static builds
1446 }
getData_() const1447 void* TlsAbstraction::getData_() const
1448 {
1449     return tlsData;
1450 }
setData_(void * pData)1451 void TlsAbstraction::setData_(void *pData)
1452 {
1453     tlsData = pData;
1454 }
1455 #else //WINRT
1456 #ifdef CV_USE_FLS
1457 static void NTAPI opencv_fls_destructor(void* pData);
1458 #endif // CV_USE_FLS
TlsAbstraction()1459 TlsAbstraction::TlsAbstraction()
1460 {
1461 #ifndef CV_USE_FLS
1462     tlsKey = TlsAlloc();
1463 #else // CV_USE_FLS
1464     tlsKey = FlsAlloc(opencv_fls_destructor);
1465 #endif // CV_USE_FLS
1466     CV_Assert(tlsKey != TLS_OUT_OF_INDEXES);
1467 }
~TlsAbstraction()1468 TlsAbstraction::~TlsAbstraction()
1469 {
1470     cv::__termination = true;  // DllMain is missing in static builds
1471 #ifndef CV_USE_FLS
1472     TlsFree(tlsKey);
1473 #else // CV_USE_FLS
1474     FlsFree(tlsKey);
1475 #endif // CV_USE_FLS
1476     tlsKey = TLS_OUT_OF_INDEXES;
1477 }
getData_() const1478 void* TlsAbstraction::getData_() const
1479 {
1480 #ifndef CV_USE_FLS
1481     return TlsGetValue(tlsKey);
1482 #else // CV_USE_FLS
1483     return FlsGetValue(tlsKey);
1484 #endif // CV_USE_FLS
1485 }
setData_(void * pData)1486 void TlsAbstraction::setData_(void *pData)
1487 {
1488 #ifndef CV_USE_FLS
1489     CV_Assert(TlsSetValue(tlsKey, pData) == TRUE);
1490 #else // CV_USE_FLS
1491     CV_Assert(FlsSetValue(tlsKey, pData) == TRUE);
1492 #endif // CV_USE_FLS
1493 }
1494 #endif // WINRT
1495 #else // _WIN32
1496 static void opencv_tls_destructor(void* pData);
TlsAbstraction()1497 TlsAbstraction::TlsAbstraction()
1498 {
1499     CV_Assert(pthread_key_create(&tlsKey, opencv_tls_destructor) == 0);
1500 }
~TlsAbstraction()1501 TlsAbstraction::~TlsAbstraction()
1502 {
1503     cv::__termination = true;  // DllMain is missing in static builds
1504     if (pthread_key_delete(tlsKey) != 0)
1505     {
1506         // Don't use logging here
1507         fprintf(stderr, "OpenCV ERROR: TlsAbstraction::~TlsAbstraction(): pthread_key_delete() call failed\n");
1508         fflush(stderr);
1509     }
1510 }
getData_() const1511 void* TlsAbstraction::getData_() const
1512 {
1513     return pthread_getspecific(tlsKey);
1514 }
setData_(void * pData)1515 void TlsAbstraction::setData_(void *pData)
1516 {
1517     CV_Assert(pthread_setspecific(tlsKey, pData) == 0);
1518 }
1519 #endif
1520 
1521 // Per-thread data structure
1522 struct ThreadData
1523 {
ThreadDatacv::details::ThreadData1524     ThreadData()
1525     {
1526         idx = 0;
1527         slots.reserve(32);
1528     }
1529 
1530     std::vector<void*> slots; // Data array for a thread
1531     size_t idx;               // Thread index in TLS storage. This is not OS thread ID!
1532 };
1533 
1534 
1535 static bool g_isTlsStorageInitialized = false;
1536 
1537 // Main TLS storage class
1538 class TlsStorage
1539 {
1540 public:
TlsStorage()1541     TlsStorage() :
1542         tlsSlotsSize(0)
1543     {
1544         tlsSlots.reserve(32);
1545         threads.reserve(32);
1546         g_isTlsStorageInitialized = true;
1547     }
~TlsStorage()1548     ~TlsStorage()
1549     {
1550         // TlsStorage object should not be released
1551         // There is no reliable way to avoid problems caused by static initialization order fiasco
1552         // Don't use logging here
1553         fprintf(stderr, "OpenCV FATAL: TlsStorage::~TlsStorage() call is not expected\n");
1554         fflush(stderr);
1555     }
1556 
releaseThread(void * tlsValue=NULL)1557     void releaseThread(void* tlsValue = NULL)
1558     {
1559         TlsAbstraction* tls = getTlsAbstraction();
1560         if (NULL == tls)
1561             return;  // TLS singleton is not available (terminated)
1562         ThreadData *pTD = tlsValue == NULL ? (ThreadData*)tls->getData() : (ThreadData*)tlsValue;
1563         if (pTD == NULL)
1564             return;  // no OpenCV TLS data for this thread
1565         AutoLock guard(mtxGlobalAccess);
1566         for (size_t i = 0; i < threads.size(); i++)
1567         {
1568             if (pTD == threads[i])
1569             {
1570                 threads[i] = NULL;
1571                 if (tlsValue == NULL)
1572                     tls->setData(0);
1573                 std::vector<void*>& thread_slots = pTD->slots;
1574                 for (size_t slotIdx = 0; slotIdx < thread_slots.size(); slotIdx++)
1575                 {
1576                     void* pData = thread_slots[slotIdx];
1577                     thread_slots[slotIdx] = NULL;
1578                     if (!pData)
1579                         continue;
1580                     TLSDataContainer* container = tlsSlots[slotIdx].container;
1581                     if (container)
1582                         container->deleteDataInstance(pData);
1583                     else
1584                     {
1585                         fprintf(stderr, "OpenCV ERROR: TLS: container for slotIdx=%d is NULL. Can't release thread data\n", (int)slotIdx);
1586                         fflush(stderr);
1587                     }
1588                 }
1589                 delete pTD;
1590                 return;
1591             }
1592         }
1593         fprintf(stderr, "OpenCV WARNING: TLS: Can't release thread TLS data (unknown pointer or data race): %p\n", (void*)pTD); fflush(stderr);
1594     }
1595 
1596     // Reserve TLS storage index
reserveSlot(TLSDataContainer * container)1597     size_t reserveSlot(TLSDataContainer* container)
1598     {
1599         AutoLock guard(mtxGlobalAccess);
1600         CV_Assert(tlsSlotsSize == tlsSlots.size());
1601 
1602         // Find unused slots
1603         for(size_t slot = 0; slot < tlsSlotsSize; slot++)
1604         {
1605             if (tlsSlots[slot].container == NULL)
1606             {
1607                 tlsSlots[slot].container = container;
1608                 return slot;
1609             }
1610         }
1611 
1612         // Create new slot
1613         tlsSlots.push_back(TlsSlotInfo(container)); tlsSlotsSize++;
1614         return tlsSlotsSize - 1;
1615     }
1616 
1617     // Release TLS storage index and pass associated data to caller
releaseSlot(size_t slotIdx,std::vector<void * > & dataVec,bool keepSlot=false)1618     void releaseSlot(size_t slotIdx, std::vector<void*> &dataVec, bool keepSlot = false)
1619     {
1620         AutoLock guard(mtxGlobalAccess);
1621         CV_Assert(tlsSlotsSize == tlsSlots.size());
1622         CV_Assert(tlsSlotsSize > slotIdx);
1623 
1624         for(size_t i = 0; i < threads.size(); i++)
1625         {
1626             if(threads[i])
1627             {
1628                 std::vector<void*>& thread_slots = threads[i]->slots;
1629                 if (thread_slots.size() > slotIdx && thread_slots[slotIdx])
1630                 {
1631                     dataVec.push_back(thread_slots[slotIdx]);
1632                     thread_slots[slotIdx] = NULL;
1633                 }
1634             }
1635         }
1636 
1637         if (!keepSlot)
1638         {
1639             tlsSlots[slotIdx].container = NULL;  // mark slot as free (see reserveSlot() implementation)
1640         }
1641     }
1642 
1643     // Get data by TLS storage index
getData(size_t slotIdx) const1644     void* getData(size_t slotIdx) const
1645     {
1646 #ifndef CV_THREAD_SANITIZER
1647         CV_Assert(tlsSlotsSize > slotIdx);
1648 #endif
1649 
1650         TlsAbstraction* tls = getTlsAbstraction();
1651         if (NULL == tls)
1652             return NULL;  // TLS singleton is not available (terminated)
1653 
1654         ThreadData* threadData = (ThreadData*)tls->getData();
1655         if(threadData && threadData->slots.size() > slotIdx)
1656             return threadData->slots[slotIdx];
1657 
1658         return NULL;
1659     }
1660 
1661     // Gather data from threads by TLS storage index
gather(size_t slotIdx,std::vector<void * > & dataVec)1662     void gather(size_t slotIdx, std::vector<void*> &dataVec)
1663     {
1664         AutoLock guard(mtxGlobalAccess);
1665         CV_Assert(tlsSlotsSize == tlsSlots.size());
1666         CV_Assert(tlsSlotsSize > slotIdx);
1667 
1668         for(size_t i = 0; i < threads.size(); i++)
1669         {
1670             if(threads[i])
1671             {
1672                 std::vector<void*>& thread_slots = threads[i]->slots;
1673                 if (thread_slots.size() > slotIdx && thread_slots[slotIdx])
1674                     dataVec.push_back(thread_slots[slotIdx]);
1675             }
1676         }
1677     }
1678 
1679     // Set data to storage index
setData(size_t slotIdx,void * pData)1680     void setData(size_t slotIdx, void* pData)
1681     {
1682 #ifndef CV_THREAD_SANITIZER
1683         CV_Assert(tlsSlotsSize > slotIdx);
1684 #endif
1685 
1686         TlsAbstraction* tls = getTlsAbstraction();
1687         if (NULL == tls)
1688             return;  // TLS singleton is not available (terminated)
1689 
1690         ThreadData* threadData = (ThreadData*)tls->getData();
1691         if(!threadData)
1692         {
1693             threadData = new ThreadData;
1694             tls->setData((void*)threadData);
1695             {
1696                 AutoLock guard(mtxGlobalAccess);
1697 
1698                 bool found = false;
1699                 // Find unused slots
1700                 for(size_t slot = 0; slot < threads.size(); slot++)
1701                 {
1702                     if (threads[slot] == NULL)
1703                     {
1704                         threadData->idx = (int)slot;
1705                         threads[slot] = threadData;
1706                         found = true;
1707                         break;
1708                     }
1709                 }
1710 
1711                 if (!found)
1712                 {
1713                     // Create new slot
1714                     threadData->idx = threads.size();
1715                     threads.push_back(threadData);
1716                 }
1717             }
1718         }
1719 
1720         if(slotIdx >= threadData->slots.size())
1721         {
1722             AutoLock guard(mtxGlobalAccess); // keep synchronization with gather() calls
1723             threadData->slots.resize(slotIdx + 1, NULL);
1724         }
1725         threadData->slots[slotIdx] = pData;
1726     }
1727 
1728 private:
1729     Mutex  mtxGlobalAccess;           // Shared objects operation guard
1730     size_t tlsSlotsSize;              // equal to tlsSlots.size() in synchronized sections
1731                                       // without synchronization this counter doesn't decrease - it is used for slotIdx sanity checks
1732 
1733     struct TlsSlotInfo
1734     {
TlsSlotInfocv::details::TlsStorage::TlsSlotInfo1735         TlsSlotInfo(TLSDataContainer* _container) : container(_container) {}
1736         TLSDataContainer* container;  // attached container (to dispose data of terminated threads)
1737     };
1738     std::vector<struct TlsSlotInfo> tlsSlots;  // TLS keys state
1739     std::vector<ThreadData*> threads; // Array for all allocated data. Thread data pointers are placed here to allow data cleanup
1740 };
1741 
1742 // Create global TLS storage object
getTlsStorage()1743 static TlsStorage &getTlsStorage()
1744 {
1745     CV_SINGLETON_LAZY_INIT_REF(TlsStorage, new TlsStorage())
1746 }
1747 
1748 #ifndef _WIN32  // pthread key destructor
opencv_tls_destructor(void * pData)1749 static void opencv_tls_destructor(void* pData)
1750 {
1751     if (!g_isTlsStorageInitialized)
1752         return;  // nothing to release, so prefer to avoid creation of new global structures
1753     getTlsStorage().releaseThread(pData);
1754 }
1755 #else // _WIN32
1756 #ifdef CV_USE_FLS
opencv_fls_destructor(void * pData)1757 static void WINAPI opencv_fls_destructor(void* pData)
1758 {
1759     // Empiric detection of ExitProcess call
1760     DWORD code = STILL_ACTIVE/*259*/;
1761     BOOL res = GetExitCodeProcess(GetCurrentProcess(), &code);
1762     if (res && code != STILL_ACTIVE)
1763     {
1764         // Looks like we are in ExitProcess() call
1765         // This is FLS specific only because their callback is called before DllMain.
1766         // TLS doesn't have similar problem, DllMain() is called first which mark __termination properly.
1767         // Note: this workaround conflicts with ExitProcess() steps order described in documentation, however it works:
1768         // 3. ... called with DLL_PROCESS_DETACH
1769         // 7. The termination status of the process changes from STILL_ACTIVE to the exit value of the process.
1770         // (ref: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-exitprocess)
1771         cv::__termination = true;
1772     }
1773 
1774     if (!g_isTlsStorageInitialized)
1775         return;  // nothing to release, so prefer to avoid creation of new global structures
1776     getTlsStorage().releaseThread(pData);
1777 }
1778 #endif // CV_USE_FLS
1779 #endif // _WIN32
1780 
1781 } // namespace details
1782 using namespace details;
1783 
releaseTlsStorageThread()1784 void releaseTlsStorageThread()
1785 {
1786     if (!g_isTlsStorageInitialized)
1787         return;  // nothing to release, so prefer to avoid creation of new global structures
1788     getTlsStorage().releaseThread();
1789 }
1790 
TLSDataContainer()1791 TLSDataContainer::TLSDataContainer()
1792 {
1793     key_ = (int)getTlsStorage().reserveSlot(this); // Reserve key from TLS storage
1794 }
1795 
~TLSDataContainer()1796 TLSDataContainer::~TLSDataContainer()
1797 {
1798     CV_Assert(key_ == -1); // Key must be released in child object
1799 }
1800 
gatherData(std::vector<void * > & data) const1801 void TLSDataContainer::gatherData(std::vector<void*> &data) const
1802 {
1803     getTlsStorage().gather(key_, data);
1804 }
1805 
detachData(std::vector<void * > & data)1806 void TLSDataContainer::detachData(std::vector<void*> &data)
1807 {
1808     getTlsStorage().releaseSlot(key_, data, true);
1809 }
1810 
release()1811 void TLSDataContainer::release()
1812 {
1813     if (key_ == -1)
1814         return;  // already released
1815     std::vector<void*> data; data.reserve(32);
1816     getTlsStorage().releaseSlot(key_, data, false); // Release key and get stored data for proper destruction
1817     key_ = -1;
1818     for(size_t i = 0; i < data.size(); i++)  // Delete all associated data
1819         deleteDataInstance(data[i]);
1820 }
1821 
cleanup()1822 void TLSDataContainer::cleanup()
1823 {
1824     std::vector<void*> data; data.reserve(32);
1825     getTlsStorage().releaseSlot(key_, data, true); // Extract stored data with removal from TLS tables
1826     for(size_t i = 0; i < data.size(); i++)  // Delete all associated data
1827         deleteDataInstance(data[i]);
1828 }
1829 
getData() const1830 void* TLSDataContainer::getData() const
1831 {
1832     CV_Assert(key_ != -1 && "Can't fetch data from terminated TLS container.");
1833     void* pData = getTlsStorage().getData(key_); // Check if data was already allocated
1834     if(!pData)
1835     {
1836         // Create new data instance and save it to TLS storage
1837         pData = createDataInstance();
1838         try
1839         {
1840             getTlsStorage().setData(key_, pData);
1841         }
1842         catch (...)
1843         {
1844             deleteDataInstance(pData);
1845             throw;
1846         }
1847     }
1848     return pData;
1849 }
1850 
getCoreTlsDataTLS()1851 static TLSData<CoreTLSData>& getCoreTlsDataTLS()
1852 {
1853     CV_SINGLETON_LAZY_INIT_REF(TLSData<CoreTLSData>, new TLSData<CoreTLSData>())
1854 }
1855 
getCoreTlsData()1856 CoreTLSData& getCoreTlsData()
1857 {
1858     return getCoreTlsDataTLS().getRef();
1859 }
1860 
1861 #if defined CVAPI_EXPORTS && defined _WIN32 && !defined WINCE
1862 #ifdef WINRT
1863     #pragma warning(disable:4447) // Disable warning 'main' signature found without threading model
1864 #endif
1865 
1866 extern "C"
1867 BOOL WINAPI DllMain(HINSTANCE, DWORD fdwReason, LPVOID lpReserved);
1868 
1869 extern "C"
DllMain(HINSTANCE,DWORD fdwReason,LPVOID lpReserved)1870 BOOL WINAPI DllMain(HINSTANCE, DWORD fdwReason, LPVOID lpReserved)
1871 {
1872     if (fdwReason == DLL_THREAD_DETACH || fdwReason == DLL_PROCESS_DETACH)
1873     {
1874         if (lpReserved != NULL) // called after ExitProcess() call
1875         {
1876             cv::__termination = true;
1877         }
1878         else
1879         {
1880             // Not allowed to free resources if lpReserved is non-null
1881             // http://msdn.microsoft.com/en-us/library/windows/desktop/ms682583.aspx
1882             releaseTlsStorageThread();
1883         }
1884     }
1885     return TRUE;
1886 }
1887 #endif
1888 
1889 
1890 namespace {
1891 
1892 #ifdef OPENCV_WITH_ITT
overrideThreadName()1893 bool overrideThreadName()
1894 {
1895     static bool param = utils::getConfigurationParameterBool("OPENCV_TRACE_ITT_SET_THREAD_NAME", false);
1896     return param;
1897 }
1898 #endif
1899 
1900 static int g_threadNum = 0;
1901 class ThreadID {
1902 public:
1903     const int id;
ThreadID()1904     ThreadID() :
1905         id(CV_XADD(&g_threadNum, 1))
1906     {
1907 #ifdef OPENCV_WITH_ITT
1908         if (overrideThreadName())
1909             __itt_thread_set_name(cv::format("OpenCVThread-%03d", id).c_str());
1910 #endif
1911     }
1912 };
1913 
getThreadIDTLS()1914 static TLSData<ThreadID>& getThreadIDTLS()
1915 {
1916     CV_SINGLETON_LAZY_INIT_REF(TLSData<ThreadID>, new TLSData<ThreadID>());
1917 }
1918 
1919 } // namespace
getThreadID()1920 int utils::getThreadID() { return getThreadIDTLS().get()->id; }
1921 
1922 
1923 class ParseError
1924 {
1925     std::string bad_value;
1926 public:
ParseError(const std::string & bad_value_)1927     ParseError(const std::string &bad_value_) :bad_value(bad_value_) {}
toString(const std::string & param) const1928     std::string toString(const std::string &param) const
1929     {
1930         std::ostringstream out;
1931         out << "Invalid value for parameter " << param << ": " << bad_value;
1932         return out.str();
1933     }
1934 };
1935 
1936 template <typename T>
1937 T parseOption(const std::string &);
1938 
1939 template<>
parseOption(const std::string & value)1940 inline bool parseOption(const std::string & value)
1941 {
1942     if (value == "1" || value == "True" || value == "true" || value == "TRUE")
1943     {
1944         return true;
1945     }
1946     if (value == "0" || value == "False" || value == "false" || value == "FALSE")
1947     {
1948         return false;
1949     }
1950     throw ParseError(value);
1951 }
1952 
1953 template<>
parseOption(const std::string & value)1954 inline size_t parseOption(const std::string &value)
1955 {
1956     size_t pos = 0;
1957     for (; pos < value.size(); pos++)
1958     {
1959         if (!isdigit(value[pos]))
1960             break;
1961     }
1962     cv::String valueStr = value.substr(0, pos);
1963     cv::String suffixStr = value.substr(pos, value.length() - pos);
1964     size_t v = (size_t)std::stoull(valueStr);
1965     if (suffixStr.length() == 0)
1966         return v;
1967     else if (suffixStr == "MB" || suffixStr == "Mb" || suffixStr == "mb")
1968         return v * 1024 * 1024;
1969     else if (suffixStr == "KB" || suffixStr == "Kb" || suffixStr == "kb")
1970         return v * 1024;
1971     throw ParseError(value);
1972 }
1973 
1974 template<>
parseOption(const std::string & value)1975 inline cv::String parseOption(const std::string &value)
1976 {
1977     return value;
1978 }
1979 
1980 template<>
parseOption(const std::string & value)1981 inline utils::Paths parseOption(const std::string &value)
1982 {
1983     utils::Paths result;
1984 #ifdef _WIN32
1985     const char sep = ';';
1986 #else
1987     const char sep = ':';
1988 #endif
1989     size_t start_pos = 0;
1990     while (start_pos != std::string::npos)
1991     {
1992         const size_t pos = value.find(sep, start_pos);
1993         const std::string one_piece(value, start_pos, pos == std::string::npos ? pos : pos - start_pos);
1994         if (!one_piece.empty())
1995             result.push_back(one_piece);
1996         start_pos = pos == std::string::npos ? pos : pos + 1;
1997     }
1998     return result;
1999 }
2000 
envRead(const char * name)2001 static inline const char * envRead(const char * name)
2002 {
2003 #ifdef NO_GETENV
2004     CV_UNUSED(name);
2005     return NULL;
2006 #else
2007     return getenv(name);
2008 #endif
2009 }
2010 
2011 template<typename T>
read(const std::string & k,const T & defaultValue)2012 inline T read(const std::string & k, const T & defaultValue)
2013 {
2014     try
2015     {
2016         const char * res = envRead(k.c_str());
2017         if (res)
2018             return parseOption<T>(std::string(res));
2019     }
2020     catch (const ParseError &err)
2021     {
2022         CV_Error(cv::Error::StsBadArg, err.toString(k));
2023     }
2024     return defaultValue;
2025 }
2026 
getConfigurationParameterBool(const char * name,bool defaultValue)2027 bool utils::getConfigurationParameterBool(const char* name, bool defaultValue)
2028 {
2029     return read<bool>(name, defaultValue);
2030 }
2031 
getConfigurationParameterSizeT(const char * name,size_t defaultValue)2032 size_t utils::getConfigurationParameterSizeT(const char* name, size_t defaultValue)
2033 {
2034     return read<size_t>(name, defaultValue);
2035 }
2036 
getConfigurationParameterString(const char * name,const char * defaultValue)2037 cv::String utils::getConfigurationParameterString(const char* name, const char* defaultValue)
2038 {
2039     return read<cv::String>(name, defaultValue ? cv::String(defaultValue) : cv::String());
2040 }
2041 
getConfigurationParameterPaths(const char * name,const utils::Paths & defaultValue)2042 utils::Paths utils::getConfigurationParameterPaths(const char* name, const utils::Paths &defaultValue)
2043 {
2044     return read<utils::Paths>(name, defaultValue);
2045 }
2046 
2047 
2048 #ifdef CV_COLLECT_IMPL_DATA
getImplData()2049 ImplCollector& getImplData()
2050 {
2051     CV_SINGLETON_LAZY_INIT_REF(ImplCollector, new ImplCollector())
2052 }
2053 
setImpl(int flags)2054 void setImpl(int flags)
2055 {
2056     cv::AutoLock lock(getImplData().mutex);
2057 
2058     getImplData().implFlags = flags;
2059     getImplData().implCode.clear();
2060     getImplData().implFun.clear();
2061 }
2062 
addImpl(int flag,const char * func)2063 void addImpl(int flag, const char* func)
2064 {
2065     cv::AutoLock lock(getImplData().mutex);
2066 
2067     getImplData().implFlags |= flag;
2068     if(func) // use lazy collection if name was not specified
2069     {
2070         size_t index = getImplData().implCode.size();
2071         if(!index || (getImplData().implCode[index-1] != flag || getImplData().implFun[index-1].compare(func))) // avoid duplicates
2072         {
2073             getImplData().implCode.push_back(flag);
2074             getImplData().implFun.push_back(func);
2075         }
2076     }
2077 }
2078 
getImpl(std::vector<int> & impl,std::vector<String> & funName)2079 int getImpl(std::vector<int> &impl, std::vector<String> &funName)
2080 {
2081     cv::AutoLock lock(getImplData().mutex);
2082 
2083     impl    = getImplData().implCode;
2084     funName = getImplData().implFun;
2085     return getImplData().implFlags; // return actual flags for lazy collection
2086 }
2087 
useCollection()2088 bool useCollection()
2089 {
2090     return getImplData().useCollection;
2091 }
2092 
setUseCollection(bool flag)2093 void setUseCollection(bool flag)
2094 {
2095     cv::AutoLock lock(getImplData().mutex);
2096 
2097     getImplData().useCollection = flag;
2098 }
2099 #endif
2100 
2101 namespace instr
2102 {
useInstrumentation()2103 bool useInstrumentation()
2104 {
2105 #ifdef ENABLE_INSTRUMENTATION
2106     return getInstrumentStruct().useInstr;
2107 #else
2108     return false;
2109 #endif
2110 }
2111 
setUseInstrumentation(bool flag)2112 void setUseInstrumentation(bool flag)
2113 {
2114 #ifdef ENABLE_INSTRUMENTATION
2115     getInstrumentStruct().useInstr = flag;
2116 #else
2117     CV_UNUSED(flag);
2118 #endif
2119 }
2120 
getTrace()2121 InstrNode* getTrace()
2122 {
2123 #ifdef ENABLE_INSTRUMENTATION
2124     return &getInstrumentStruct().rootNode;
2125 #else
2126     return NULL;
2127 #endif
2128 }
2129 
resetTrace()2130 void resetTrace()
2131 {
2132 #ifdef ENABLE_INSTRUMENTATION
2133     getInstrumentStruct().rootNode.removeChilds();
2134     getInstrumentTLSStruct().pCurrentNode = &getInstrumentStruct().rootNode;
2135 #endif
2136 }
2137 
setFlags(FLAGS modeFlags)2138 void setFlags(FLAGS modeFlags)
2139 {
2140 #ifdef ENABLE_INSTRUMENTATION
2141     getInstrumentStruct().flags = modeFlags;
2142 #else
2143     CV_UNUSED(modeFlags);
2144 #endif
2145 }
getFlags()2146 FLAGS getFlags()
2147 {
2148 #ifdef ENABLE_INSTRUMENTATION
2149     return (FLAGS)getInstrumentStruct().flags;
2150 #else
2151     return (FLAGS)0;
2152 #endif
2153 }
2154 
NodeData(const char * funName,const char * fileName,int lineNum,void * retAddress,bool alwaysExpand,cv::instr::TYPE instrType,cv::instr::IMPL implType)2155 NodeData::NodeData(const char* funName, const char* fileName, int lineNum, void* retAddress, bool alwaysExpand, cv::instr::TYPE instrType, cv::instr::IMPL implType)
2156 {
2157     m_funName       = funName ? cv::String(funName) : cv::String();  // std::string doesn't accept NULL
2158     m_instrType     = instrType;
2159     m_implType      = implType;
2160     m_fileName      = fileName;
2161     m_lineNum       = lineNum;
2162     m_retAddress    = retAddress;
2163     m_alwaysExpand  = alwaysExpand;
2164 
2165     m_threads    = 1;
2166     m_counter    = 0;
2167     m_ticksTotal = 0;
2168 
2169     m_funError  = false;
2170 }
NodeData(NodeData & ref)2171 NodeData::NodeData(NodeData &ref)
2172 {
2173     *this = ref;
2174 }
operator =(const NodeData & right)2175 NodeData& NodeData::operator=(const NodeData &right)
2176 {
2177     this->m_funName      = right.m_funName;
2178     this->m_instrType    = right.m_instrType;
2179     this->m_implType     = right.m_implType;
2180     this->m_fileName     = right.m_fileName;
2181     this->m_lineNum      = right.m_lineNum;
2182     this->m_retAddress   = right.m_retAddress;
2183     this->m_alwaysExpand = right.m_alwaysExpand;
2184 
2185     this->m_threads     = right.m_threads;
2186     this->m_counter     = right.m_counter;
2187     this->m_ticksTotal  = right.m_ticksTotal;
2188 
2189     this->m_funError    = right.m_funError;
2190 
2191     return *this;
2192 }
~NodeData()2193 NodeData::~NodeData()
2194 {
2195 }
operator ==(const NodeData & left,const NodeData & right)2196 bool operator==(const NodeData& left, const NodeData& right)
2197 {
2198     if(left.m_lineNum == right.m_lineNum && left.m_funName == right.m_funName && left.m_fileName == right.m_fileName)
2199     {
2200         if(left.m_retAddress == right.m_retAddress || !(cv::instr::getFlags()&cv::instr::FLAGS_EXPAND_SAME_NAMES || left.m_alwaysExpand))
2201             return true;
2202     }
2203     return false;
2204 }
2205 
2206 #ifdef ENABLE_INSTRUMENTATION
getInstrumentStruct()2207 InstrStruct& getInstrumentStruct()
2208 {
2209     static InstrStruct instr;
2210     return instr;
2211 }
2212 
getInstrumentTLSStruct()2213 InstrTLSStruct& getInstrumentTLSStruct()
2214 {
2215     return *getInstrumentStruct().tlsStruct.get();
2216 }
2217 
getCurrentNode()2218 InstrNode* getCurrentNode()
2219 {
2220     return getInstrumentTLSStruct().pCurrentNode;
2221 }
2222 
IntrumentationRegion(const char * funName,const char * fileName,int lineNum,void * retAddress,bool alwaysExpand,TYPE instrType,IMPL implType)2223 IntrumentationRegion::IntrumentationRegion(const char* funName, const char* fileName, int lineNum, void *retAddress, bool alwaysExpand, TYPE instrType, IMPL implType)
2224 {
2225     m_disabled    = false;
2226     m_regionTicks = 0;
2227 
2228     InstrStruct *pStruct = &getInstrumentStruct();
2229     if(pStruct->useInstr)
2230     {
2231         InstrTLSStruct *pTLS = &getInstrumentTLSStruct();
2232 
2233         // Disable in case of failure
2234         if(!pTLS->pCurrentNode)
2235         {
2236             m_disabled = true;
2237             return;
2238         }
2239 
2240         int depth = pTLS->pCurrentNode->getDepth();
2241         if(pStruct->maxDepth && pStruct->maxDepth <= depth)
2242         {
2243             m_disabled = true;
2244             return;
2245         }
2246 
2247         NodeData payload(funName, fileName, lineNum, retAddress, alwaysExpand, instrType, implType);
2248         Node<NodeData>* pChild = NULL;
2249 
2250         if(pStruct->flags&FLAGS_MAPPING)
2251         {
2252             // Critical section
2253             cv::AutoLock guard(pStruct->mutexCreate); // Guard from concurrent child creation
2254             pChild = pTLS->pCurrentNode->findChild(payload);
2255             if(!pChild)
2256             {
2257                 pChild = new Node<NodeData>(payload);
2258                 pTLS->pCurrentNode->addChild(pChild);
2259             }
2260         }
2261         else
2262         {
2263             pChild = pTLS->pCurrentNode->findChild(payload);
2264             if(!pChild)
2265             {
2266                 m_disabled = true;
2267                 return;
2268             }
2269         }
2270         pTLS->pCurrentNode = pChild;
2271 
2272         m_regionTicks = getTickCount();
2273     }
2274 }
2275 
~IntrumentationRegion()2276 IntrumentationRegion::~IntrumentationRegion()
2277 {
2278     InstrStruct *pStruct = &getInstrumentStruct();
2279     if(pStruct->useInstr)
2280     {
2281         if(!m_disabled)
2282         {
2283             InstrTLSStruct *pTLS = &getInstrumentTLSStruct();
2284 
2285             if (pTLS->pCurrentNode->m_payload.m_implType == cv::instr::IMPL_OPENCL &&
2286                 (pTLS->pCurrentNode->m_payload.m_instrType == cv::instr::TYPE_FUN ||
2287                     pTLS->pCurrentNode->m_payload.m_instrType == cv::instr::TYPE_WRAPPER))
2288             {
2289                 cv::ocl::finish(); // TODO Support "async" OpenCL instrumentation
2290             }
2291 
2292             uint64 ticks = (getTickCount() - m_regionTicks);
2293             {
2294                 cv::AutoLock guard(pStruct->mutexCount); // Concurrent ticks accumulation
2295                 pTLS->pCurrentNode->m_payload.m_counter++;
2296                 pTLS->pCurrentNode->m_payload.m_ticksTotal += ticks;
2297                 pTLS->pCurrentNode->m_payload.m_tls.get()->m_ticksTotal += ticks;
2298             }
2299 
2300             pTLS->pCurrentNode = pTLS->pCurrentNode->m_pParent;
2301         }
2302     }
2303 }
2304 #endif
2305 }
2306 
2307 namespace ipp
2308 {
2309 
2310 #ifdef HAVE_IPP
2311 struct IPPInitSingleton
2312 {
2313 public:
IPPInitSingletoncv::ipp::IPPInitSingleton2314     IPPInitSingleton()
2315     {
2316         useIPP         = true;
2317         useIPP_NE      = false;
2318         ippStatus      = 0;
2319         funcname       = NULL;
2320         filename       = NULL;
2321         linen          = 0;
2322         cpuFeatures    = 0;
2323         ippFeatures    = 0;
2324         ippTopFeatures = 0;
2325         pIppLibInfo    = NULL;
2326 
2327         ippStatus = ippGetCpuFeatures(&cpuFeatures, NULL);
2328         if(ippStatus < 0)
2329         {
2330             std::cerr << "ERROR: IPP cannot detect CPU features, IPP was disabled " << std::endl;
2331             useIPP = false;
2332             return;
2333         }
2334         ippFeatures = cpuFeatures;
2335 
2336         const char* pIppEnv = getenv("OPENCV_IPP");
2337         cv::String env;
2338         if(pIppEnv != NULL)
2339             env = pIppEnv;
2340         if(env.size())
2341         {
2342 #if IPP_VERSION_X100 >= 201900
2343             const Ipp64u minorFeatures = ippCPUID_MOVBE|ippCPUID_AES|ippCPUID_CLMUL|ippCPUID_ABR|ippCPUID_RDRAND|ippCPUID_F16C|
2344                 ippCPUID_ADCOX|ippCPUID_RDSEED|ippCPUID_PREFETCHW|ippCPUID_SHA|ippCPUID_MPX|ippCPUID_AVX512CD|ippCPUID_AVX512ER|
2345                 ippCPUID_AVX512PF|ippCPUID_AVX512BW|ippCPUID_AVX512DQ|ippCPUID_AVX512VL|ippCPUID_AVX512VBMI|ippCPUID_AVX512_4FMADDPS|
2346                 ippCPUID_AVX512_4VNNIW|ippCPUID_AVX512IFMA;
2347 #elif IPP_VERSION_X100 >= 201703
2348             const Ipp64u minorFeatures = ippCPUID_MOVBE|ippCPUID_AES|ippCPUID_CLMUL|ippCPUID_ABR|ippCPUID_RDRAND|ippCPUID_F16C|
2349                 ippCPUID_ADCOX|ippCPUID_RDSEED|ippCPUID_PREFETCHW|ippCPUID_SHA|ippCPUID_MPX|ippCPUID_AVX512CD|ippCPUID_AVX512ER|
2350                 ippCPUID_AVX512PF|ippCPUID_AVX512BW|ippCPUID_AVX512DQ|ippCPUID_AVX512VL|ippCPUID_AVX512VBMI;
2351 #elif IPP_VERSION_X100 >= 201700
2352             const Ipp64u minorFeatures = ippCPUID_MOVBE|ippCPUID_AES|ippCPUID_CLMUL|ippCPUID_ABR|ippCPUID_RDRAND|ippCPUID_F16C|
2353                 ippCPUID_ADCOX|ippCPUID_RDSEED|ippCPUID_PREFETCHW|ippCPUID_SHA|ippCPUID_AVX512CD|ippCPUID_AVX512ER|
2354                 ippCPUID_AVX512PF|ippCPUID_AVX512BW|ippCPUID_AVX512DQ|ippCPUID_AVX512VL|ippCPUID_AVX512VBMI;
2355 #else
2356             const Ipp64u minorFeatures = 0;
2357 #endif
2358 
2359             env = toLowerCase(env);
2360             if(env.substr(0, 2) == "ne")
2361             {
2362                 useIPP_NE = true;
2363                 env = env.substr(3, env.size());
2364             }
2365 
2366             if(env == "disabled")
2367             {
2368                 std::cerr << "WARNING: IPP was disabled by OPENCV_IPP environment variable" << std::endl;
2369                 useIPP = false;
2370             }
2371             else if(env == "sse42")
2372                 ippFeatures = minorFeatures|ippCPUID_SSE2|ippCPUID_SSE3|ippCPUID_SSSE3|ippCPUID_SSE41|ippCPUID_SSE42;
2373             else if(env == "avx2")
2374                 ippFeatures = minorFeatures|ippCPUID_SSE2|ippCPUID_SSE3|ippCPUID_SSSE3|ippCPUID_SSE41|ippCPUID_SSE42|ippCPUID_AVX|ippCPUID_AVX2;
2375 #if IPP_VERSION_X100 >= 201700
2376 #if defined (_M_AMD64) || defined (__x86_64__)
2377             else if(env == "avx512")
2378                 ippFeatures = minorFeatures|ippCPUID_SSE2|ippCPUID_SSE3|ippCPUID_SSSE3|ippCPUID_SSE41|ippCPUID_SSE42|ippCPUID_AVX|ippCPUID_AVX2|ippCPUID_AVX512F;
2379 #endif
2380 #endif
2381             else
2382                 std::cerr << "ERROR: Improper value of OPENCV_IPP: " << env.c_str() << ". Correct values are: disabled, sse42, avx2, avx512 (Intel64 only)" << std::endl;
2383 
2384             // Trim unsupported features
2385             ippFeatures &= cpuFeatures;
2386         }
2387 
2388         // Disable AVX1 since we don't track regressions for it. SSE42 will be used instead
2389         if(cpuFeatures&ippCPUID_AVX && !(cpuFeatures&ippCPUID_AVX2))
2390             ippFeatures &= ~((Ipp64u)ippCPUID_AVX);
2391 
2392         // IPP integrations in OpenCV support only SSE4.2, AVX2 and AVX-512 optimizations.
2393         if(!(
2394 #if IPP_VERSION_X100 >= 201700
2395             cpuFeatures&ippCPUID_AVX512F ||
2396 #endif
2397             cpuFeatures&ippCPUID_AVX2 ||
2398             cpuFeatures&ippCPUID_SSE42
2399             ))
2400         {
2401             useIPP = false;
2402             return;
2403         }
2404 
2405         if(ippFeatures == cpuFeatures)
2406             IPP_INITIALIZER(0)
2407         else
2408             IPP_INITIALIZER(ippFeatures)
2409         ippFeatures = ippGetEnabledCpuFeatures();
2410 
2411         // Detect top level optimizations to make comparison easier for optimizations dependent conditions
2412 #if IPP_VERSION_X100 >= 201700
2413         if(ippFeatures&ippCPUID_AVX512F)
2414         {
2415             if((ippFeatures&ippCPUID_AVX512_SKX) == ippCPUID_AVX512_SKX)
2416                 ippTopFeatures = ippCPUID_AVX512_SKX;
2417             else if((ippFeatures&ippCPUID_AVX512_KNL) == ippCPUID_AVX512_KNL)
2418                 ippTopFeatures = ippCPUID_AVX512_KNL;
2419             else
2420                 ippTopFeatures = ippCPUID_AVX512F; // Unknown AVX512 configuration
2421         }
2422         else
2423 #endif
2424         if(ippFeatures&ippCPUID_AVX2)
2425             ippTopFeatures = ippCPUID_AVX2;
2426         else if(ippFeatures&ippCPUID_SSE42)
2427             ippTopFeatures = ippCPUID_SSE42;
2428 
2429         pIppLibInfo = ippiGetLibVersion();
2430 
2431         // workaround: https://github.com/opencv/opencv/issues/12959
2432         std::string ippName(pIppLibInfo->Name ? pIppLibInfo->Name : "");
2433         if (ippName.find("SSE4.2") != std::string::npos)
2434         {
2435             ippTopFeatures = ippCPUID_SSE42;
2436         }
2437     }
2438 
2439 public:
2440     bool        useIPP;
2441     bool        useIPP_NE;
2442 
2443     int         ippStatus;  // 0 - all is ok, -1 - IPP functions failed
2444     const char *funcname;
2445     const char *filename;
2446     int         linen;
2447     Ipp64u      ippFeatures;
2448     Ipp64u      cpuFeatures;
2449     Ipp64u      ippTopFeatures;
2450     const IppLibraryVersion *pIppLibInfo;
2451 };
2452 
getIPPSingleton()2453 static IPPInitSingleton& getIPPSingleton()
2454 {
2455     CV_SINGLETON_LAZY_INIT_REF(IPPInitSingleton, new IPPInitSingleton())
2456 }
2457 #endif
2458 
getIppFeatures()2459 unsigned long long getIppFeatures()
2460 {
2461 #ifdef HAVE_IPP
2462     return getIPPSingleton().ippFeatures;
2463 #else
2464     return 0;
2465 #endif
2466 }
2467 
2468 #ifdef HAVE_IPP
getIppTopFeatures()2469 unsigned long long getIppTopFeatures()
2470 {
2471     return getIPPSingleton().ippTopFeatures;
2472 }
2473 #endif
2474 
setIppStatus(int status,const char * const _funcname,const char * const _filename,int _line)2475 void setIppStatus(int status, const char * const _funcname, const char * const _filename, int _line)
2476 {
2477 #ifdef HAVE_IPP
2478     getIPPSingleton().ippStatus = status;
2479     getIPPSingleton().funcname = _funcname;
2480     getIPPSingleton().filename = _filename;
2481     getIPPSingleton().linen = _line;
2482 #else
2483     CV_UNUSED(status); CV_UNUSED(_funcname); CV_UNUSED(_filename); CV_UNUSED(_line);
2484 #endif
2485 }
2486 
getIppStatus()2487 int getIppStatus()
2488 {
2489 #ifdef HAVE_IPP
2490     return getIPPSingleton().ippStatus;
2491 #else
2492     return 0;
2493 #endif
2494 }
2495 
getIppErrorLocation()2496 String getIppErrorLocation()
2497 {
2498 #ifdef HAVE_IPP
2499     return format("%s:%d %s", getIPPSingleton().filename ? getIPPSingleton().filename : "", getIPPSingleton().linen, getIPPSingleton().funcname ? getIPPSingleton().funcname : "");
2500 #else
2501     return String();
2502 #endif
2503 }
2504 
getIppVersion()2505 String getIppVersion()
2506 {
2507 #ifdef HAVE_IPP
2508     const IppLibraryVersion *pInfo = getIPPSingleton().pIppLibInfo;
2509     if(pInfo)
2510         return format("%s %s %s", pInfo->Name, pInfo->Version, pInfo->BuildDate);
2511     else
2512         return String("error");
2513 #else
2514     return String("disabled");
2515 #endif
2516 }
2517 
useIPP()2518 bool useIPP()
2519 {
2520 #ifdef HAVE_IPP
2521     CoreTLSData& data = getCoreTlsData();
2522     if (data.useIPP < 0)
2523     {
2524         data.useIPP = getIPPSingleton().useIPP;
2525     }
2526     return (data.useIPP > 0);
2527 #else
2528     return false;
2529 #endif
2530 }
2531 
setUseIPP(bool flag)2532 void setUseIPP(bool flag)
2533 {
2534     CoreTLSData& data = getCoreTlsData();
2535 #ifdef HAVE_IPP
2536     data.useIPP = (getIPPSingleton().useIPP)?flag:false;
2537 #else
2538     CV_UNUSED(flag);
2539     data.useIPP = false;
2540 #endif
2541 }
2542 
useIPP_NotExact()2543 bool useIPP_NotExact()
2544 {
2545 #ifdef HAVE_IPP
2546     CoreTLSData& data = getCoreTlsData();
2547     if (data.useIPP_NE < 0)
2548     {
2549         data.useIPP_NE = getIPPSingleton().useIPP_NE;
2550     }
2551     return (data.useIPP_NE > 0);
2552 #else
2553     return false;
2554 #endif
2555 }
2556 
setUseIPP_NotExact(bool flag)2557 void setUseIPP_NotExact(bool flag)
2558 {
2559     CoreTLSData& data = getCoreTlsData();
2560 #ifdef HAVE_IPP
2561     data.useIPP_NE = flag;
2562 #else
2563     CV_UNUSED(flag);
2564     data.useIPP_NE = false;
2565 #endif
2566 }
2567 
2568 } // namespace ipp
2569 
2570 } // namespace cv
2571 
2572 /* End of file. */
2573