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

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

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