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

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of opencv/modules/core/src/system.cpp