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 ¶m) 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