2010-05-12 01:44:00 +08:00
|
|
|
/*M///////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
|
|
|
//
|
|
|
|
// By downloading, copying, installing or using the software you agree to this license.
|
|
|
|
// If you do not agree to this license, do not download, install,
|
|
|
|
// copy or use the software.
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// License Agreement
|
|
|
|
// For Open Source Computer Vision Library
|
|
|
|
//
|
|
|
|
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
|
|
|
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
2015-01-12 15:59:30 +08:00
|
|
|
// Copyright (C) 2015, Itseez Inc., all rights reserved.
|
2010-05-12 01:44:00 +08:00
|
|
|
// Third party copyrights are property of their respective owners.
|
|
|
|
//
|
|
|
|
// Redistribution and use in source and binary forms, with or without modification,
|
|
|
|
// are permitted provided that the following conditions are met:
|
|
|
|
//
|
|
|
|
// * Redistribution's of source code must retain the above copyright notice,
|
|
|
|
// this list of conditions and the following disclaimer.
|
|
|
|
//
|
|
|
|
// * Redistribution's in binary form must reproduce the above copyright notice,
|
|
|
|
// this list of conditions and the following disclaimer in the documentation
|
|
|
|
// and/or other materials provided with the distribution.
|
|
|
|
//
|
|
|
|
// * The name of the copyright holders may not be used to endorse or promote products
|
|
|
|
// derived from this software without specific prior written permission.
|
|
|
|
//
|
|
|
|
// This software is provided by the copyright holders and contributors "as is" and
|
|
|
|
// any express or implied warranties, including, but not limited to, the implied
|
|
|
|
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
|
|
|
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
|
|
|
// indirect, incidental, special, exemplary, or consequential damages
|
|
|
|
// (including, but not limited to, procurement of substitute goods or services;
|
|
|
|
// loss of use, data, or profits; or business interruption) however caused
|
|
|
|
// and on any theory of liability, whether in contract, strict liability,
|
|
|
|
// or tort (including negligence or otherwise) arising in any way out of
|
|
|
|
// the use of this software, even if advised of the possibility of such damage.
|
|
|
|
//
|
|
|
|
//M*/
|
|
|
|
|
|
|
|
#include "precomp.hpp"
|
2015-09-25 23:00:53 +08:00
|
|
|
#include <iostream>
|
2010-05-12 01:44:00 +08:00
|
|
|
|
2015-06-23 19:31:01 +08:00
|
|
|
namespace cv {
|
|
|
|
|
|
|
|
static Mutex* __initialization_mutex = NULL;
|
|
|
|
Mutex& getInitializationMutex()
|
|
|
|
{
|
|
|
|
if (__initialization_mutex == NULL)
|
|
|
|
__initialization_mutex = new Mutex();
|
|
|
|
return *__initialization_mutex;
|
|
|
|
}
|
|
|
|
// force initialization (single-threaded environment)
|
|
|
|
Mutex* __initialization_mutex_initializer = &getInitializationMutex();
|
|
|
|
|
|
|
|
} // namespace cv
|
|
|
|
|
2013-08-21 18:38:20 +08:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
# if _MSC_VER >= 1700
|
|
|
|
# pragma warning(disable:4447) // Disable warning 'main' signature found without threading model
|
|
|
|
# endif
|
|
|
|
#endif
|
|
|
|
|
2015-11-13 16:03:34 +08:00
|
|
|
#if defined ANDROID || defined __linux__ || defined __FreeBSD__
|
2014-12-30 21:53:19 +08:00
|
|
|
# include <unistd.h>
|
|
|
|
# include <fcntl.h>
|
|
|
|
# include <elf.h>
|
2015-11-13 16:03:34 +08:00
|
|
|
#if defined ANDROID || defined __linux__
|
2014-12-30 21:53:19 +08:00
|
|
|
# include <linux/auxvec.h>
|
|
|
|
#endif
|
2015-11-13 16:03:34 +08:00
|
|
|
#endif
|
2014-12-30 21:53:19 +08:00
|
|
|
|
2010-07-17 06:38:57 +08:00
|
|
|
#if defined WIN32 || defined _WIN32 || defined WINCE
|
2012-11-01 16:44:10 +08:00
|
|
|
#ifndef _WIN32_WINNT // This is needed for the declaration of TryEnterCriticalSection in winbase.h with Visual Studio 2005 (and older?)
|
|
|
|
#define _WIN32_WINNT 0x0400 // http://msdn.microsoft.com/en-us/library/ms686857(VS.85).aspx
|
|
|
|
#endif
|
|
|
|
#include <windows.h>
|
2013-07-19 17:43:05 +08:00
|
|
|
#if (_WIN32_WINNT >= 0x0602)
|
2013-07-23 21:44:57 +08:00
|
|
|
#include <synchapi.h>
|
2013-07-19 17:43:05 +08:00
|
|
|
#endif
|
2012-11-01 16:44:10 +08:00
|
|
|
#undef small
|
|
|
|
#undef min
|
|
|
|
#undef max
|
|
|
|
#undef abs
|
2010-05-12 01:44:00 +08:00
|
|
|
#include <tchar.h>
|
2015-12-15 20:55:43 +08:00
|
|
|
#if defined _MSC_VER
|
|
|
|
#if _MSC_VER >= 1400
|
|
|
|
#include <intrin.h>
|
|
|
|
#elif defined _M_IX86
|
|
|
|
static void __cpuid(int* cpuid_data, int)
|
|
|
|
{
|
|
|
|
__asm
|
|
|
|
{
|
|
|
|
push ebx
|
|
|
|
push edi
|
|
|
|
mov edi, cpuid_data
|
|
|
|
mov eax, 1
|
|
|
|
cpuid
|
|
|
|
mov [edi], eax
|
|
|
|
mov [edi + 4], ebx
|
|
|
|
mov [edi + 8], ecx
|
|
|
|
mov [edi + 12], edx
|
|
|
|
pop edi
|
|
|
|
pop ebx
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static void __cpuidex(int* cpuid_data, int, int)
|
|
|
|
{
|
|
|
|
__asm
|
|
|
|
{
|
|
|
|
push edi
|
|
|
|
mov edi, cpuid_data
|
|
|
|
mov eax, 7
|
|
|
|
mov ecx, 0
|
|
|
|
cpuid
|
|
|
|
mov [edi], eax
|
|
|
|
mov [edi + 4], ebx
|
|
|
|
mov [edi + 8], ecx
|
|
|
|
mov [edi + 12], edx
|
|
|
|
pop edi
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
2013-07-19 17:43:05 +08:00
|
|
|
|
2015-02-21 00:47:45 +08:00
|
|
|
#ifdef WINRT
|
2013-07-19 17:43:05 +08:00
|
|
|
#include <wrl/client.h>
|
2013-11-18 20:25:50 +08:00
|
|
|
#ifndef __cplusplus_winrt
|
|
|
|
#include <windows.storage.h>
|
|
|
|
#pragma comment(lib, "runtimeobject.lib")
|
|
|
|
#endif
|
2013-07-19 17:43:05 +08:00
|
|
|
|
|
|
|
std::wstring GetTempPathWinRT()
|
|
|
|
{
|
2013-11-18 20:25:50 +08:00
|
|
|
#ifdef __cplusplus_winrt
|
2013-07-19 17:43:05 +08:00
|
|
|
return std::wstring(Windows::Storage::ApplicationData::Current->TemporaryFolder->Path->Data());
|
2013-11-18 20:25:50 +08:00
|
|
|
#else
|
|
|
|
Microsoft::WRL::ComPtr<ABI::Windows::Storage::IApplicationDataStatics> appdataFactory;
|
|
|
|
Microsoft::WRL::ComPtr<ABI::Windows::Storage::IApplicationData> appdataRef;
|
|
|
|
Microsoft::WRL::ComPtr<ABI::Windows::Storage::IStorageFolder> storagefolderRef;
|
|
|
|
Microsoft::WRL::ComPtr<ABI::Windows::Storage::IStorageItem> storageitemRef;
|
|
|
|
HSTRING str;
|
|
|
|
HSTRING_HEADER hstrHead;
|
|
|
|
std::wstring wstr;
|
|
|
|
if (FAILED(WindowsCreateStringReference(RuntimeClass_Windows_Storage_ApplicationData,
|
|
|
|
(UINT32)wcslen(RuntimeClass_Windows_Storage_ApplicationData), &hstrHead, &str)))
|
|
|
|
return wstr;
|
2013-12-23 00:21:51 +08:00
|
|
|
if (FAILED(RoGetActivationFactory(str, IID_PPV_ARGS(appdataFactory.ReleaseAndGetAddressOf()))))
|
2013-11-18 20:25:50 +08:00
|
|
|
return wstr;
|
|
|
|
if (FAILED(appdataFactory->get_Current(appdataRef.ReleaseAndGetAddressOf())))
|
|
|
|
return wstr;
|
|
|
|
if (FAILED(appdataRef->get_TemporaryFolder(storagefolderRef.ReleaseAndGetAddressOf())))
|
|
|
|
return wstr;
|
|
|
|
if (FAILED(storagefolderRef.As(&storageitemRef)))
|
|
|
|
return wstr;
|
|
|
|
str = NULL;
|
|
|
|
if (FAILED(storageitemRef->get_Path(&str)))
|
|
|
|
return wstr;
|
|
|
|
wstr = WindowsGetStringRawBuffer(str, NULL);
|
|
|
|
WindowsDeleteString(str);
|
|
|
|
return wstr;
|
|
|
|
#endif
|
2013-07-19 17:43:05 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
std::wstring GetTempFileNameWinRT(std::wstring prefix)
|
|
|
|
{
|
2013-07-29 19:38:18 +08:00
|
|
|
wchar_t guidStr[40];
|
|
|
|
GUID g;
|
|
|
|
CoCreateGuid(&g);
|
2013-07-19 17:43:05 +08:00
|
|
|
wchar_t* mask = L"%08x_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x";
|
2013-07-29 19:38:18 +08:00
|
|
|
swprintf(&guidStr[0], sizeof(guidStr)/sizeof(wchar_t), mask,
|
|
|
|
g.Data1, g.Data2, g.Data3, UINT(g.Data4[0]), UINT(g.Data4[1]),
|
|
|
|
UINT(g.Data4[2]), UINT(g.Data4[3]), UINT(g.Data4[4]),
|
|
|
|
UINT(g.Data4[5]), UINT(g.Data4[6]), UINT(g.Data4[7]));
|
2013-07-19 17:43:05 +08:00
|
|
|
|
2015-02-21 00:47:45 +08:00
|
|
|
return prefix.append(std::wstring(guidStr));
|
2013-07-19 17:43:05 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
2010-05-12 01:44:00 +08:00
|
|
|
#else
|
|
|
|
#include <pthread.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <time.h>
|
|
|
|
|
2011-06-13 04:29:50 +08:00
|
|
|
#if defined __MACH__ && defined __APPLE__
|
2010-05-12 01:44:00 +08:00
|
|
|
#include <mach/mach.h>
|
|
|
|
#include <mach/mach_time.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef _OPENMP
|
|
|
|
#include "omp.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
2016-08-22 21:17:06 +08:00
|
|
|
#if defined __linux__ || defined __APPLE__ || defined __EMSCRIPTEN__ || defined __FreeBSD__
|
2011-08-02 20:42:58 +08:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdio.h>
|
2012-06-08 01:21:29 +08:00
|
|
|
#include <sys/types.h>
|
2011-08-02 22:56:51 +08:00
|
|
|
#if defined ANDROID
|
|
|
|
#include <sys/sysconf.h>
|
2011-08-02 20:42:58 +08:00
|
|
|
#endif
|
2011-08-02 22:56:51 +08:00
|
|
|
#endif
|
2011-08-02 20:42:58 +08:00
|
|
|
|
2012-08-08 20:39:24 +08:00
|
|
|
#ifdef ANDROID
|
|
|
|
# include <android/log.h>
|
|
|
|
#endif
|
|
|
|
|
2010-05-12 01:44:00 +08:00
|
|
|
namespace cv
|
|
|
|
{
|
|
|
|
|
2011-06-09 05:35:19 +08:00
|
|
|
Exception::Exception() { code = 0; line = 0; }
|
|
|
|
|
2013-03-23 00:37:49 +08:00
|
|
|
Exception::Exception(int _code, const String& _err, const String& _func, const String& _file, int _line)
|
2011-06-09 05:35:19 +08:00
|
|
|
: code(_code), err(_err), func(_func), file(_file), line(_line)
|
|
|
|
{
|
|
|
|
formatMessage();
|
|
|
|
}
|
|
|
|
|
|
|
|
Exception::~Exception() throw() {}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\return the error description and the context as a text string.
|
2012-06-08 01:21:29 +08:00
|
|
|
*/
|
2011-06-09 05:35:19 +08:00
|
|
|
const char* Exception::what() const throw() { return msg.c_str(); }
|
|
|
|
|
|
|
|
void Exception::formatMessage()
|
|
|
|
{
|
|
|
|
if( func.size() > 0 )
|
|
|
|
msg = format("%s:%d: error: (%d) %s in function %s\n", file.c_str(), line, code, err.c_str(), func.c_str());
|
|
|
|
else
|
|
|
|
msg = format("%s:%d: error: (%d) %s\n", file.c_str(), line, code, err.c_str());
|
|
|
|
}
|
2012-06-08 01:21:29 +08:00
|
|
|
|
2015-12-15 20:55:43 +08:00
|
|
|
struct HWFeatures
|
|
|
|
{
|
|
|
|
enum { MAX_FEATURE = CV_HARDWARE_MAX_FEATURE };
|
|
|
|
|
|
|
|
HWFeatures(void)
|
|
|
|
{
|
|
|
|
memset( have, 0, sizeof(have) );
|
|
|
|
x86_family = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HWFeatures initialize(void)
|
|
|
|
{
|
|
|
|
HWFeatures f;
|
|
|
|
int cpuid_data[4] = { 0, 0, 0, 0 };
|
|
|
|
|
|
|
|
#if defined _MSC_VER && (defined _M_IX86 || defined _M_X64)
|
|
|
|
__cpuid(cpuid_data, 1);
|
|
|
|
#elif defined __GNUC__ && (defined __i386__ || defined __x86_64__)
|
|
|
|
#ifdef __x86_64__
|
|
|
|
asm __volatile__
|
|
|
|
(
|
|
|
|
"movl $1, %%eax\n\t"
|
|
|
|
"cpuid\n\t"
|
|
|
|
:[eax]"=a"(cpuid_data[0]),[ebx]"=b"(cpuid_data[1]),[ecx]"=c"(cpuid_data[2]),[edx]"=d"(cpuid_data[3])
|
|
|
|
:
|
|
|
|
: "cc"
|
|
|
|
);
|
|
|
|
#else
|
|
|
|
asm volatile
|
|
|
|
(
|
|
|
|
"pushl %%ebx\n\t"
|
|
|
|
"movl $1,%%eax\n\t"
|
|
|
|
"cpuid\n\t"
|
|
|
|
"popl %%ebx\n\t"
|
|
|
|
: "=a"(cpuid_data[0]), "=c"(cpuid_data[2]), "=d"(cpuid_data[3])
|
|
|
|
:
|
|
|
|
: "cc"
|
|
|
|
);
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
f.x86_family = (cpuid_data[0] >> 8) & 15;
|
|
|
|
if( f.x86_family >= 6 )
|
|
|
|
{
|
|
|
|
f.have[CV_CPU_MMX] = (cpuid_data[3] & (1 << 23)) != 0;
|
|
|
|
f.have[CV_CPU_SSE] = (cpuid_data[3] & (1<<25)) != 0;
|
|
|
|
f.have[CV_CPU_SSE2] = (cpuid_data[3] & (1<<26)) != 0;
|
|
|
|
f.have[CV_CPU_SSE3] = (cpuid_data[2] & (1<<0)) != 0;
|
|
|
|
f.have[CV_CPU_SSSE3] = (cpuid_data[2] & (1<<9)) != 0;
|
|
|
|
f.have[CV_CPU_FMA3] = (cpuid_data[2] & (1<<12)) != 0;
|
|
|
|
f.have[CV_CPU_SSE4_1] = (cpuid_data[2] & (1<<19)) != 0;
|
|
|
|
f.have[CV_CPU_SSE4_2] = (cpuid_data[2] & (1<<20)) != 0;
|
|
|
|
f.have[CV_CPU_POPCNT] = (cpuid_data[2] & (1<<23)) != 0;
|
|
|
|
f.have[CV_CPU_AVX] = (((cpuid_data[2] & (1<<28)) != 0)&&((cpuid_data[2] & (1<<27)) != 0));//OS uses XSAVE_XRSTORE and CPU support AVX
|
2016-05-21 20:31:33 +08:00
|
|
|
f.have[CV_CPU_FP16] = (cpuid_data[2] & (1<<29)) != 0;
|
2015-12-15 20:55:43 +08:00
|
|
|
|
|
|
|
// make the second call to the cpuid command in order to get
|
|
|
|
// information about extended features like AVX2
|
|
|
|
#if defined _MSC_VER && (defined _M_IX86 || defined _M_X64)
|
|
|
|
__cpuidex(cpuid_data, 7, 0);
|
|
|
|
#elif defined __GNUC__ && (defined __i386__ || defined __x86_64__)
|
|
|
|
#ifdef __x86_64__
|
|
|
|
asm __volatile__
|
|
|
|
(
|
|
|
|
"movl $7, %%eax\n\t"
|
|
|
|
"movl $0, %%ecx\n\t"
|
|
|
|
"cpuid\n\t"
|
|
|
|
:[eax]"=a"(cpuid_data[0]),[ebx]"=b"(cpuid_data[1]),[ecx]"=c"(cpuid_data[2]),[edx]"=d"(cpuid_data[3])
|
|
|
|
:
|
|
|
|
: "cc"
|
|
|
|
);
|
|
|
|
#else
|
|
|
|
asm volatile
|
|
|
|
(
|
|
|
|
"pushl %%ebx\n\t"
|
|
|
|
"movl $7,%%eax\n\t"
|
|
|
|
"movl $0,%%ecx\n\t"
|
|
|
|
"cpuid\n\t"
|
|
|
|
"movl %%ebx, %0\n\t"
|
|
|
|
"popl %%ebx\n\t"
|
|
|
|
: "=r"(cpuid_data[1]), "=c"(cpuid_data[2])
|
|
|
|
:
|
|
|
|
: "cc"
|
|
|
|
);
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
f.have[CV_CPU_AVX2] = (cpuid_data[1] & (1<<5)) != 0;
|
|
|
|
|
|
|
|
f.have[CV_CPU_AVX_512F] = (cpuid_data[1] & (1<<16)) != 0;
|
|
|
|
f.have[CV_CPU_AVX_512DQ] = (cpuid_data[1] & (1<<17)) != 0;
|
|
|
|
f.have[CV_CPU_AVX_512IFMA512] = (cpuid_data[1] & (1<<21)) != 0;
|
|
|
|
f.have[CV_CPU_AVX_512PF] = (cpuid_data[1] & (1<<26)) != 0;
|
|
|
|
f.have[CV_CPU_AVX_512ER] = (cpuid_data[1] & (1<<27)) != 0;
|
|
|
|
f.have[CV_CPU_AVX_512CD] = (cpuid_data[1] & (1<<28)) != 0;
|
|
|
|
f.have[CV_CPU_AVX_512BW] = (cpuid_data[1] & (1<<30)) != 0;
|
|
|
|
f.have[CV_CPU_AVX_512VL] = (cpuid_data[1] & (1<<31)) != 0;
|
|
|
|
f.have[CV_CPU_AVX_512VBMI] = (cpuid_data[2] & (1<<1)) != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined ANDROID || defined __linux__
|
|
|
|
#ifdef __aarch64__
|
|
|
|
f.have[CV_CPU_NEON] = true;
|
2016-05-21 20:31:33 +08:00
|
|
|
f.have[CV_CPU_FP16] = true;
|
|
|
|
#elif defined __arm__
|
2015-12-15 20:55:43 +08:00
|
|
|
int cpufile = open("/proc/self/auxv", O_RDONLY);
|
|
|
|
|
|
|
|
if (cpufile >= 0)
|
|
|
|
{
|
|
|
|
Elf32_auxv_t auxv;
|
|
|
|
const size_t size_auxv_t = sizeof(auxv);
|
|
|
|
|
|
|
|
while ((size_t)read(cpufile, &auxv, size_auxv_t) == size_auxv_t)
|
|
|
|
{
|
|
|
|
if (auxv.a_type == AT_HWCAP)
|
|
|
|
{
|
|
|
|
f.have[CV_CPU_NEON] = (auxv.a_un.a_val & 4096) != 0;
|
2016-05-21 20:31:33 +08:00
|
|
|
f.have[CV_CPU_FP16] = (auxv.a_un.a_val & 2) != 0;
|
2015-12-15 20:55:43 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
close(cpufile);
|
|
|
|
}
|
|
|
|
#endif
|
2016-05-21 20:31:33 +08:00
|
|
|
#elif (defined __clang__ || defined __APPLE__)
|
|
|
|
#if (defined __ARM_NEON__ || (defined __ARM_NEON && defined __aarch64__))
|
2015-12-15 20:55:43 +08:00
|
|
|
f.have[CV_CPU_NEON] = true;
|
2016-05-21 20:31:33 +08:00
|
|
|
#endif
|
|
|
|
#if (defined __ARM_FP && (((__ARM_FP & 0x2) != 0) && defined __ARM_NEON__))
|
|
|
|
f.have[CV_CPU_FP16] = true;
|
|
|
|
#endif
|
2015-12-15 20:55:43 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
|
|
|
int x86_family;
|
|
|
|
bool have[MAX_FEATURE+1];
|
|
|
|
};
|
|
|
|
|
|
|
|
static HWFeatures featuresEnabled = HWFeatures::initialize(), featuresDisabled = HWFeatures();
|
|
|
|
static HWFeatures* currentFeatures = &featuresEnabled;
|
|
|
|
|
2010-05-12 01:44:00 +08:00
|
|
|
bool checkHardwareSupport(int feature)
|
|
|
|
{
|
|
|
|
CV_DbgAssert( 0 <= feature && feature <= CV_HARDWARE_MAX_FEATURE );
|
2015-12-15 20:55:43 +08:00
|
|
|
return currentFeatures->have[feature];
|
2010-05-12 01:44:00 +08:00
|
|
|
}
|
|
|
|
|
2015-12-15 20:55:43 +08:00
|
|
|
|
|
|
|
volatile bool useOptimizedFlag = true;
|
|
|
|
|
2010-05-12 01:44:00 +08:00
|
|
|
void setUseOptimized( bool flag )
|
|
|
|
{
|
2015-12-15 20:55:43 +08:00
|
|
|
useOptimizedFlag = flag;
|
|
|
|
currentFeatures = flag ? &featuresEnabled : &featuresDisabled;
|
2015-02-27 19:24:51 +08:00
|
|
|
|
|
|
|
ipp::setUseIPP(flag);
|
2015-06-20 01:52:14 +08:00
|
|
|
#ifdef HAVE_OPENCL
|
2015-02-27 19:24:51 +08:00
|
|
|
ocl::setUseOpenCL(flag);
|
2015-06-20 01:52:14 +08:00
|
|
|
#endif
|
2015-02-27 19:24:51 +08:00
|
|
|
#ifdef HAVE_TEGRA_OPTIMIZATION
|
|
|
|
::tegra::setUseTegra(flag);
|
|
|
|
#endif
|
2010-05-12 01:44:00 +08:00
|
|
|
}
|
|
|
|
|
2010-12-24 07:00:04 +08:00
|
|
|
bool useOptimized(void)
|
2010-05-12 01:44:00 +08:00
|
|
|
{
|
2015-12-15 20:55:43 +08:00
|
|
|
return useOptimizedFlag;
|
2010-05-12 01:44:00 +08:00
|
|
|
}
|
2010-12-24 07:00:04 +08:00
|
|
|
|
|
|
|
int64 getTickCount(void)
|
2010-05-12 01:44:00 +08:00
|
|
|
{
|
2010-07-17 06:38:57 +08:00
|
|
|
#if defined WIN32 || defined _WIN32 || defined WINCE
|
2010-05-12 01:44:00 +08:00
|
|
|
LARGE_INTEGER counter;
|
|
|
|
QueryPerformanceCounter( &counter );
|
|
|
|
return (int64)counter.QuadPart;
|
|
|
|
#elif defined __linux || defined __linux__
|
|
|
|
struct timespec tp;
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &tp);
|
|
|
|
return (int64)tp.tv_sec*1000000000 + tp.tv_nsec;
|
2011-05-31 23:22:22 +08:00
|
|
|
#elif defined __MACH__ && defined __APPLE__
|
2010-05-12 01:44:00 +08:00
|
|
|
return (int64)mach_absolute_time();
|
2010-12-24 07:00:04 +08:00
|
|
|
#else
|
2010-05-12 01:44:00 +08:00
|
|
|
struct timeval tv;
|
|
|
|
struct timezone tz;
|
|
|
|
gettimeofday( &tv, &tz );
|
|
|
|
return (int64)tv.tv_sec*1000000 + tv.tv_usec;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2010-12-24 07:00:04 +08:00
|
|
|
double getTickFrequency(void)
|
2010-05-12 01:44:00 +08:00
|
|
|
{
|
2010-07-17 06:38:57 +08:00
|
|
|
#if defined WIN32 || defined _WIN32 || defined WINCE
|
2010-05-12 01:44:00 +08:00
|
|
|
LARGE_INTEGER freq;
|
|
|
|
QueryPerformanceFrequency(&freq);
|
|
|
|
return (double)freq.QuadPart;
|
|
|
|
#elif defined __linux || defined __linux__
|
|
|
|
return 1e9;
|
2011-05-31 23:22:22 +08:00
|
|
|
#elif defined __MACH__ && defined __APPLE__
|
2010-05-12 01:44:00 +08:00
|
|
|
static double freq = 0;
|
|
|
|
if( freq == 0 )
|
|
|
|
{
|
|
|
|
mach_timebase_info_data_t sTimebaseInfo;
|
|
|
|
mach_timebase_info(&sTimebaseInfo);
|
|
|
|
freq = sTimebaseInfo.denom*1e9/sTimebaseInfo.numer;
|
|
|
|
}
|
2010-12-24 07:00:04 +08:00
|
|
|
return freq;
|
2010-05-12 01:44:00 +08:00
|
|
|
#else
|
|
|
|
return 1e6;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2010-12-24 07:00:04 +08:00
|
|
|
#if defined __GNUC__ && (defined __i386__ || defined __x86_64__ || defined __ppc__)
|
2010-05-12 01:44:00 +08:00
|
|
|
#if defined(__i386__)
|
|
|
|
|
|
|
|
int64 getCPUTickCount(void)
|
|
|
|
{
|
|
|
|
int64 x;
|
|
|
|
__asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
#elif defined(__x86_64__)
|
|
|
|
|
|
|
|
int64 getCPUTickCount(void)
|
|
|
|
{
|
|
|
|
unsigned hi, lo;
|
|
|
|
__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
|
|
|
|
return (int64)lo | ((int64)hi << 32);
|
|
|
|
}
|
|
|
|
|
|
|
|
#elif defined(__ppc__)
|
|
|
|
|
|
|
|
int64 getCPUTickCount(void)
|
|
|
|
{
|
2010-12-24 07:00:04 +08:00
|
|
|
int64 result = 0;
|
2010-05-12 01:44:00 +08:00
|
|
|
unsigned upper, lower, tmp;
|
|
|
|
__asm__ volatile(
|
|
|
|
"0: \n"
|
|
|
|
"\tmftbu %0 \n"
|
|
|
|
"\tmftb %1 \n"
|
|
|
|
"\tmftbu %2 \n"
|
|
|
|
"\tcmpw %2,%0 \n"
|
|
|
|
"\tbne 0b \n"
|
|
|
|
: "=r"(upper),"=r"(lower),"=r"(tmp)
|
|
|
|
);
|
|
|
|
return lower | ((int64)upper << 32);
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
#error "RDTSC not defined"
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2010-07-17 06:38:57 +08:00
|
|
|
#elif defined _MSC_VER && defined WIN32 && defined _M_IX86
|
2010-05-12 01:44:00 +08:00
|
|
|
|
|
|
|
int64 getCPUTickCount(void)
|
|
|
|
{
|
|
|
|
__asm _emit 0x0f;
|
|
|
|
__asm _emit 0x31;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
2014-03-21 19:27:56 +08:00
|
|
|
//#ifdef HAVE_IPP
|
|
|
|
//int64 getCPUTickCount(void)
|
|
|
|
//{
|
|
|
|
// return ippGetCpuClocks();
|
|
|
|
//}
|
|
|
|
//#else
|
2010-12-24 07:00:04 +08:00
|
|
|
int64 getCPUTickCount(void)
|
2010-05-12 01:44:00 +08:00
|
|
|
{
|
|
|
|
return getTickCount();
|
|
|
|
}
|
2014-03-21 19:27:56 +08:00
|
|
|
//#endif
|
2010-05-12 01:44:00 +08:00
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2013-03-23 00:37:49 +08:00
|
|
|
const String& getBuildInformation()
|
2012-04-14 05:50:59 +08:00
|
|
|
{
|
2013-03-23 00:37:49 +08:00
|
|
|
static String build_info =
|
2012-04-14 05:50:59 +08:00
|
|
|
#include "version_string.inc"
|
|
|
|
;
|
|
|
|
return build_info;
|
|
|
|
}
|
|
|
|
|
2013-03-23 00:37:49 +08:00
|
|
|
String format( const char* fmt, ... )
|
2010-05-12 01:44:00 +08:00
|
|
|
{
|
2014-03-25 03:07:00 +08:00
|
|
|
AutoBuffer<char, 1024> buf;
|
2013-03-26 15:54:04 +08:00
|
|
|
|
2014-03-25 03:07:00 +08:00
|
|
|
for ( ; ; )
|
2013-03-26 15:54:04 +08:00
|
|
|
{
|
2014-03-25 03:07:00 +08:00
|
|
|
va_list va;
|
2013-03-26 15:54:04 +08:00
|
|
|
va_start(va, fmt);
|
2014-03-25 03:07:00 +08:00
|
|
|
int bsize = static_cast<int>(buf.size()),
|
|
|
|
len = vsnprintf((char *)buf, bsize, fmt, va);
|
2013-03-26 15:54:04 +08:00
|
|
|
va_end(va);
|
|
|
|
|
2014-03-25 03:07:00 +08:00
|
|
|
if (len < 0 || len >= bsize)
|
|
|
|
{
|
|
|
|
buf.resize(std::max(bsize << 1, len + 1));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
return String((char *)buf, len);
|
|
|
|
}
|
2010-05-12 01:44:00 +08:00
|
|
|
}
|
|
|
|
|
2013-03-23 00:37:49 +08:00
|
|
|
String tempfile( const char* suffix )
|
2011-04-11 22:47:06 +08:00
|
|
|
{
|
2013-03-23 00:37:49 +08:00
|
|
|
String fname;
|
2015-02-21 00:47:45 +08:00
|
|
|
#ifndef WINRT
|
2014-05-06 04:59:39 +08:00
|
|
|
const char *temp_dir = getenv("OPENCV_TEMP_PATH");
|
2013-07-19 17:43:05 +08:00
|
|
|
#endif
|
2012-12-08 19:43:23 +08:00
|
|
|
|
2012-06-25 19:24:06 +08:00
|
|
|
#if defined WIN32 || defined _WIN32
|
2015-02-21 00:47:45 +08:00
|
|
|
#ifdef WINRT
|
2013-07-19 17:43:05 +08:00
|
|
|
RoInitialize(RO_INIT_MULTITHREADED);
|
2015-03-04 15:35:06 +08:00
|
|
|
std::wstring temp_dir = GetTempPathWinRT();
|
2013-07-19 17:43:05 +08:00
|
|
|
|
2015-03-04 15:35:06 +08:00
|
|
|
std::wstring temp_file = GetTempFileNameWinRT(L"ocv");
|
2013-07-19 17:43:05 +08:00
|
|
|
if (temp_file.empty())
|
2014-05-06 04:59:39 +08:00
|
|
|
return String();
|
2013-07-19 17:43:05 +08:00
|
|
|
|
2015-02-21 00:47:45 +08:00
|
|
|
temp_file = temp_dir.append(std::wstring(L"\\")).append(temp_file);
|
2013-07-19 17:43:05 +08:00
|
|
|
DeleteFileW(temp_file.c_str());
|
|
|
|
|
2013-08-19 16:25:53 +08:00
|
|
|
char aname[MAX_PATH];
|
|
|
|
size_t copied = wcstombs(aname, temp_file.c_str(), MAX_PATH);
|
|
|
|
CV_Assert((copied != MAX_PATH) && (copied != (size_t)-1));
|
2014-05-06 04:59:39 +08:00
|
|
|
fname = String(aname);
|
2013-07-19 17:43:05 +08:00
|
|
|
RoUninitialize();
|
|
|
|
#else
|
2013-08-19 16:25:53 +08:00
|
|
|
char temp_dir2[MAX_PATH] = { 0 };
|
|
|
|
char temp_file[MAX_PATH] = { 0 };
|
2012-06-25 19:24:06 +08:00
|
|
|
|
2012-12-08 19:43:23 +08:00
|
|
|
if (temp_dir == 0 || temp_dir[0] == 0)
|
|
|
|
{
|
|
|
|
::GetTempPathA(sizeof(temp_dir2), temp_dir2);
|
|
|
|
temp_dir = temp_dir2;
|
|
|
|
}
|
2012-07-02 20:23:57 +08:00
|
|
|
if(0 == ::GetTempFileNameA(temp_dir, "ocv", 0, temp_file))
|
2013-03-23 00:37:49 +08:00
|
|
|
return String();
|
2012-06-25 19:24:06 +08:00
|
|
|
|
2012-10-04 13:44:29 +08:00
|
|
|
DeleteFileA(temp_file);
|
|
|
|
|
2012-12-08 19:43:23 +08:00
|
|
|
fname = temp_file;
|
2013-07-19 17:43:05 +08:00
|
|
|
#endif
|
2012-06-25 19:24:06 +08:00
|
|
|
# else
|
|
|
|
# ifdef ANDROID
|
|
|
|
//char defaultTemplate[] = "/mnt/sdcard/__opencv_temp.XXXXXX";
|
|
|
|
char defaultTemplate[] = "/data/local/tmp/__opencv_temp.XXXXXX";
|
|
|
|
# else
|
|
|
|
char defaultTemplate[] = "/tmp/__opencv_temp.XXXXXX";
|
|
|
|
# endif
|
|
|
|
|
2012-12-08 19:43:23 +08:00
|
|
|
if (temp_dir == 0 || temp_dir[0] == 0)
|
2012-06-25 19:24:06 +08:00
|
|
|
fname = defaultTemplate;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fname = temp_dir;
|
|
|
|
char ech = fname[fname.size() - 1];
|
|
|
|
if(ech != '/' && ech != '\\')
|
2013-03-20 21:53:13 +08:00
|
|
|
fname = fname + "/";
|
|
|
|
fname = fname + "__opencv_temp.XXXXXX";
|
2012-06-25 19:24:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
const int fd = mkstemp((char*)fname.c_str());
|
2013-03-23 00:37:49 +08:00
|
|
|
if (fd == -1) return String();
|
2012-12-08 19:43:23 +08:00
|
|
|
|
2012-06-25 19:24:06 +08:00
|
|
|
close(fd);
|
|
|
|
remove(fname.c_str());
|
2012-12-08 19:43:23 +08:00
|
|
|
# endif
|
2012-06-25 19:24:06 +08:00
|
|
|
|
2012-12-08 19:43:23 +08:00
|
|
|
if (suffix)
|
2012-06-25 19:24:06 +08:00
|
|
|
{
|
|
|
|
if (suffix[0] != '.')
|
2012-12-08 19:43:23 +08:00
|
|
|
return fname + "." + suffix;
|
2012-06-25 19:24:06 +08:00
|
|
|
else
|
2012-12-08 19:43:23 +08:00
|
|
|
return fname + suffix;
|
2012-06-25 19:24:06 +08:00
|
|
|
}
|
|
|
|
return fname;
|
2011-04-11 22:47:06 +08:00
|
|
|
}
|
|
|
|
|
2010-05-12 01:44:00 +08:00
|
|
|
static CvErrorCallback customErrorCallback = 0;
|
|
|
|
static void* customErrorCallbackData = 0;
|
|
|
|
static bool breakOnError = false;
|
|
|
|
|
|
|
|
bool setBreakOnError(bool value)
|
|
|
|
{
|
|
|
|
bool prevVal = breakOnError;
|
|
|
|
breakOnError = value;
|
|
|
|
return prevVal;
|
2010-12-24 07:00:04 +08:00
|
|
|
}
|
2010-05-12 01:44:00 +08:00
|
|
|
|
|
|
|
void error( const Exception& exc )
|
|
|
|
{
|
2010-12-24 07:00:04 +08:00
|
|
|
if (customErrorCallback != 0)
|
2010-05-12 01:44:00 +08:00
|
|
|
customErrorCallback(exc.code, exc.func.c_str(), exc.err.c_str(),
|
|
|
|
exc.file.c_str(), exc.line, customErrorCallbackData);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const char* errorStr = cvErrorStr(exc.code);
|
|
|
|
char buf[1 << 16];
|
|
|
|
|
|
|
|
sprintf( buf, "OpenCV Error: %s (%s) in %s, file %s, line %d",
|
|
|
|
errorStr, exc.err.c_str(), exc.func.size() > 0 ?
|
|
|
|
exc.func.c_str() : "unknown function", exc.file.c_str(), exc.line );
|
|
|
|
fprintf( stderr, "%s\n", buf );
|
|
|
|
fflush( stderr );
|
2013-01-23 16:27:30 +08:00
|
|
|
# ifdef __ANDROID__
|
2012-08-08 20:39:24 +08:00
|
|
|
__android_log_print(ANDROID_LOG_ERROR, "cv::error()", "%s", buf);
|
|
|
|
# endif
|
2010-05-12 01:44:00 +08:00
|
|
|
}
|
2010-12-24 07:00:04 +08:00
|
|
|
|
2010-05-12 01:44:00 +08:00
|
|
|
if(breakOnError)
|
|
|
|
{
|
|
|
|
static volatile int* p = 0;
|
|
|
|
*p = 0;
|
|
|
|
}
|
2010-12-24 07:00:04 +08:00
|
|
|
|
2010-05-12 01:44:00 +08:00
|
|
|
throw exc;
|
|
|
|
}
|
2010-12-24 07:00:04 +08:00
|
|
|
|
2013-03-27 22:43:06 +08:00
|
|
|
void error(int _code, const String& _err, const char* _func, const char* _file, int _line)
|
|
|
|
{
|
|
|
|
error(cv::Exception(_code, _err, _func, _file, _line));
|
|
|
|
}
|
|
|
|
|
2010-05-12 01:44:00 +08:00
|
|
|
CvErrorCallback
|
|
|
|
redirectError( CvErrorCallback errCallback, void* userdata, void** prevUserdata)
|
|
|
|
{
|
|
|
|
if( prevUserdata )
|
|
|
|
*prevUserdata = customErrorCallbackData;
|
2010-12-24 07:00:04 +08:00
|
|
|
|
2010-05-12 01:44:00 +08:00
|
|
|
CvErrorCallback prevCallback = customErrorCallback;
|
2010-12-24 07:00:04 +08:00
|
|
|
|
|
|
|
customErrorCallback = errCallback;
|
2010-05-12 01:44:00 +08:00
|
|
|
customErrorCallbackData = userdata;
|
2010-12-24 07:00:04 +08:00
|
|
|
|
2010-05-12 01:44:00 +08:00
|
|
|
return prevCallback;
|
|
|
|
}
|
2010-12-24 07:00:04 +08:00
|
|
|
|
2010-05-12 01:44:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
CV_IMPL int cvCheckHardwareSupport(int feature)
|
|
|
|
{
|
|
|
|
CV_DbgAssert( 0 <= feature && feature <= CV_HARDWARE_MAX_FEATURE );
|
2015-12-15 20:55:43 +08:00
|
|
|
return cv::currentFeatures->have[feature];
|
2010-05-12 01:44:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
CV_IMPL int cvUseOptimized( int flag )
|
|
|
|
{
|
2015-12-15 20:55:43 +08:00
|
|
|
int prevMode = cv::useOptimizedFlag;
|
2010-05-12 01:44:00 +08:00
|
|
|
cv::setUseOptimized( flag != 0 );
|
|
|
|
return prevMode;
|
|
|
|
}
|
|
|
|
|
|
|
|
CV_IMPL int64 cvGetTickCount(void)
|
|
|
|
{
|
|
|
|
return cv::getTickCount();
|
|
|
|
}
|
|
|
|
|
|
|
|
CV_IMPL double cvGetTickFrequency(void)
|
|
|
|
{
|
|
|
|
return cv::getTickFrequency()*1e-6;
|
|
|
|
}
|
|
|
|
|
|
|
|
CV_IMPL CvErrorCallback
|
|
|
|
cvRedirectError( CvErrorCallback errCallback, void* userdata, void** prevUserdata)
|
|
|
|
{
|
|
|
|
return cv::redirectError(errCallback, userdata, prevUserdata);
|
|
|
|
}
|
|
|
|
|
|
|
|
CV_IMPL int cvNulDevReport( int, const char*, const char*,
|
|
|
|
const char*, int, void* )
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
CV_IMPL int cvStdErrReport( int, const char*, const char*,
|
|
|
|
const char*, int, void* )
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
CV_IMPL int cvGuiBoxReport( int, const char*, const char*,
|
|
|
|
const char*, int, void* )
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
CV_IMPL int cvGetErrInfo( const char**, const char**, const char**, int* )
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CV_IMPL const char* cvErrorStr( int status )
|
|
|
|
{
|
|
|
|
static char buf[256];
|
|
|
|
|
|
|
|
switch (status)
|
|
|
|
{
|
2010-12-24 07:00:04 +08:00
|
|
|
case CV_StsOk : return "No Error";
|
|
|
|
case CV_StsBackTrace : return "Backtrace";
|
|
|
|
case CV_StsError : return "Unspecified error";
|
|
|
|
case CV_StsInternal : return "Internal error";
|
|
|
|
case CV_StsNoMem : return "Insufficient memory";
|
|
|
|
case CV_StsBadArg : return "Bad argument";
|
|
|
|
case CV_StsNoConv : return "Iterations do not converge";
|
|
|
|
case CV_StsAutoTrace : return "Autotrace call";
|
|
|
|
case CV_StsBadSize : return "Incorrect size of input array";
|
|
|
|
case CV_StsNullPtr : return "Null pointer";
|
|
|
|
case CV_StsDivByZero : return "Division by zero occured";
|
|
|
|
case CV_BadStep : return "Image step is wrong";
|
2010-05-12 01:44:00 +08:00
|
|
|
case CV_StsInplaceNotSupported : return "Inplace operation is not supported";
|
|
|
|
case CV_StsObjectNotFound : return "Requested object was not found";
|
2010-12-24 07:00:04 +08:00
|
|
|
case CV_BadDepth : return "Input image depth is not supported by function";
|
|
|
|
case CV_StsUnmatchedFormats : return "Formats of input arguments do not match";
|
|
|
|
case CV_StsUnmatchedSizes : return "Sizes of input arguments do not match";
|
|
|
|
case CV_StsOutOfRange : return "One of arguments\' values is out of range";
|
|
|
|
case CV_StsUnsupportedFormat : return "Unsupported format or combination of formats";
|
|
|
|
case CV_BadCOI : return "Input COI is not supported";
|
|
|
|
case CV_BadNumChannels : return "Bad number of channels";
|
|
|
|
case CV_StsBadFlag : return "Bad flag (parameter or structure field)";
|
|
|
|
case CV_StsBadPoint : return "Bad parameter of type CvPoint";
|
|
|
|
case CV_StsBadMask : return "Bad type of mask argument";
|
|
|
|
case CV_StsParseError : return "Parsing error";
|
|
|
|
case CV_StsNotImplemented : return "The function/feature is not implemented";
|
|
|
|
case CV_StsBadMemBlock : return "Memory block has been corrupted";
|
|
|
|
case CV_StsAssert : return "Assertion failed";
|
2013-07-24 17:55:18 +08:00
|
|
|
case CV_GpuNotSupported : return "No CUDA support";
|
2011-11-21 19:58:52 +08:00
|
|
|
case CV_GpuApiCallError : return "Gpu API call";
|
|
|
|
case CV_OpenGlNotSupported : return "No OpenGL support";
|
|
|
|
case CV_OpenGlApiCallError : return "OpenGL API call";
|
2010-05-12 01:44:00 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
sprintf(buf, "Unknown %s code %d", status >= 0 ? "status":"error", status);
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
CV_IMPL int cvGetErrMode(void)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
CV_IMPL int cvSetErrMode(int)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-12-24 07:00:04 +08:00
|
|
|
CV_IMPL int cvGetErrStatus(void)
|
2010-05-12 01:44:00 +08:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
CV_IMPL void cvSetErrStatus(int)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CV_IMPL void cvError( int code, const char* func_name,
|
|
|
|
const char* err_msg,
|
|
|
|
const char* file_name, int line )
|
|
|
|
{
|
|
|
|
cv::error(cv::Exception(code, err_msg, func_name, file_name, line));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* function, which converts int to int */
|
|
|
|
CV_IMPL int
|
|
|
|
cvErrorFromIppStatus( int status )
|
|
|
|
{
|
|
|
|
switch (status)
|
|
|
|
{
|
2010-12-24 07:00:04 +08:00
|
|
|
case CV_BADSIZE_ERR: return CV_StsBadSize;
|
|
|
|
case CV_BADMEMBLOCK_ERR: return CV_StsBadMemBlock;
|
|
|
|
case CV_NULLPTR_ERR: return CV_StsNullPtr;
|
|
|
|
case CV_DIV_BY_ZERO_ERR: return CV_StsDivByZero;
|
|
|
|
case CV_BADSTEP_ERR: return CV_BadStep;
|
|
|
|
case CV_OUTOFMEM_ERR: return CV_StsNoMem;
|
|
|
|
case CV_BADARG_ERR: return CV_StsBadArg;
|
|
|
|
case CV_NOTDEFINED_ERR: return CV_StsError;
|
2010-05-12 01:44:00 +08:00
|
|
|
case CV_INPLACE_NOT_SUPPORTED_ERR: return CV_StsInplaceNotSupported;
|
2010-12-24 07:00:04 +08:00
|
|
|
case CV_NOTFOUND_ERR: return CV_StsObjectNotFound;
|
|
|
|
case CV_BADCONVERGENCE_ERR: return CV_StsNoConv;
|
|
|
|
case CV_BADDEPTH_ERR: return CV_BadDepth;
|
|
|
|
case CV_UNMATCHED_FORMATS_ERR: return CV_StsUnmatchedFormats;
|
|
|
|
case CV_UNSUPPORTED_COI_ERR: return CV_BadCOI;
|
|
|
|
case CV_UNSUPPORTED_CHANNELS_ERR: return CV_BadNumChannels;
|
|
|
|
case CV_BADFLAG_ERR: return CV_StsBadFlag;
|
|
|
|
case CV_BADRANGE_ERR: return CV_StsBadArg;
|
|
|
|
case CV_BADCOEF_ERR: return CV_StsBadArg;
|
|
|
|
case CV_BADFACTOR_ERR: return CV_StsBadArg;
|
|
|
|
case CV_BADPOINT_ERR: return CV_StsBadPoint;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return CV_StsError;
|
2010-05-12 01:44:00 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-11 04:31:34 +08:00
|
|
|
namespace cv {
|
|
|
|
bool __termination = false;
|
|
|
|
}
|
2010-05-12 01:44:00 +08:00
|
|
|
|
2012-08-17 21:32:06 +08:00
|
|
|
namespace cv
|
|
|
|
{
|
|
|
|
|
|
|
|
#if defined WIN32 || defined _WIN32 || defined WINCE
|
|
|
|
|
|
|
|
struct Mutex::Impl
|
|
|
|
{
|
2013-07-19 17:43:05 +08:00
|
|
|
Impl()
|
|
|
|
{
|
|
|
|
#if (_WIN32_WINNT >= 0x0600)
|
|
|
|
::InitializeCriticalSectionEx(&cs, 1000, 0);
|
|
|
|
#else
|
|
|
|
::InitializeCriticalSection(&cs);
|
|
|
|
#endif
|
|
|
|
refcount = 1;
|
|
|
|
}
|
2012-08-17 21:32:06 +08:00
|
|
|
~Impl() { DeleteCriticalSection(&cs); }
|
2012-08-17 22:28:50 +08:00
|
|
|
|
2012-08-17 21:32:06 +08:00
|
|
|
void lock() { EnterCriticalSection(&cs); }
|
|
|
|
bool trylock() { return TryEnterCriticalSection(&cs) != 0; }
|
|
|
|
void unlock() { LeaveCriticalSection(&cs); }
|
2012-08-17 22:28:50 +08:00
|
|
|
|
2012-08-17 21:32:06 +08:00
|
|
|
CRITICAL_SECTION cs;
|
|
|
|
int refcount;
|
|
|
|
};
|
2012-10-17 07:18:30 +08:00
|
|
|
|
2012-08-17 21:32:06 +08:00
|
|
|
#else
|
|
|
|
|
|
|
|
struct Mutex::Impl
|
|
|
|
{
|
2013-11-22 17:00:37 +08:00
|
|
|
Impl()
|
|
|
|
{
|
|
|
|
pthread_mutexattr_t attr;
|
|
|
|
pthread_mutexattr_init(&attr);
|
|
|
|
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
|
|
|
pthread_mutex_init(&mt, &attr);
|
|
|
|
pthread_mutexattr_destroy(&attr);
|
|
|
|
|
|
|
|
refcount = 1;
|
|
|
|
}
|
|
|
|
~Impl() { pthread_mutex_destroy(&mt); }
|
2012-08-17 22:28:50 +08:00
|
|
|
|
2013-11-22 17:00:37 +08:00
|
|
|
void lock() { pthread_mutex_lock(&mt); }
|
|
|
|
bool trylock() { return pthread_mutex_trylock(&mt) == 0; }
|
|
|
|
void unlock() { pthread_mutex_unlock(&mt); }
|
2012-08-17 22:28:50 +08:00
|
|
|
|
2013-11-22 17:00:37 +08:00
|
|
|
pthread_mutex_t mt;
|
2012-08-17 21:32:06 +08:00
|
|
|
int refcount;
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
Mutex::Mutex()
|
|
|
|
{
|
|
|
|
impl = new Mutex::Impl;
|
|
|
|
}
|
2012-08-17 22:28:50 +08:00
|
|
|
|
2012-08-17 21:32:06 +08:00
|
|
|
Mutex::~Mutex()
|
|
|
|
{
|
|
|
|
if( CV_XADD(&impl->refcount, -1) == 1 )
|
|
|
|
delete impl;
|
|
|
|
impl = 0;
|
|
|
|
}
|
2012-08-17 22:28:50 +08:00
|
|
|
|
2012-08-17 21:32:06 +08:00
|
|
|
Mutex::Mutex(const Mutex& m)
|
|
|
|
{
|
|
|
|
impl = m.impl;
|
|
|
|
CV_XADD(&impl->refcount, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
Mutex& Mutex::operator = (const Mutex& m)
|
|
|
|
{
|
|
|
|
CV_XADD(&m.impl->refcount, 1);
|
|
|
|
if( CV_XADD(&impl->refcount, -1) == 1 )
|
|
|
|
delete impl;
|
|
|
|
impl = m.impl;
|
|
|
|
return *this;
|
|
|
|
}
|
2012-08-17 22:28:50 +08:00
|
|
|
|
2012-08-17 21:32:06 +08:00
|
|
|
void Mutex::lock() { impl->lock(); }
|
|
|
|
void Mutex::unlock() { impl->unlock(); }
|
2012-08-17 22:28:50 +08:00
|
|
|
bool Mutex::trylock() { return impl->trylock(); }
|
2012-08-17 21:32:06 +08:00
|
|
|
|
2013-12-11 22:49:13 +08:00
|
|
|
|
|
|
|
//////////////////////////////// thread-local storage ////////////////////////////////
|
|
|
|
|
2015-08-12 21:23:02 +08:00
|
|
|
#ifdef WIN32
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
#pragma warning(disable:4505) // unreferenced local function has been removed
|
|
|
|
#endif
|
|
|
|
#ifndef TLS_OUT_OF_INDEXES
|
|
|
|
#define TLS_OUT_OF_INDEXES ((DWORD)0xFFFFFFFF)
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// TLS platform abstraction layer
|
|
|
|
class TlsAbstraction
|
2013-12-11 22:49:13 +08:00
|
|
|
{
|
|
|
|
public:
|
2015-08-12 21:23:02 +08:00
|
|
|
TlsAbstraction();
|
|
|
|
~TlsAbstraction();
|
|
|
|
void* GetData() const;
|
|
|
|
void SetData(void *pData);
|
2013-12-11 22:49:13 +08:00
|
|
|
|
2015-08-12 21:23:02 +08:00
|
|
|
private:
|
2013-12-11 22:49:13 +08:00
|
|
|
#ifdef WIN32
|
2015-08-12 21:23:02 +08:00
|
|
|
#ifndef WINRT
|
|
|
|
DWORD tlsKey;
|
2013-12-30 16:31:00 +08:00
|
|
|
#endif
|
2015-08-12 21:23:02 +08:00
|
|
|
#else // WIN32
|
|
|
|
pthread_key_t tlsKey;
|
|
|
|
#endif
|
|
|
|
};
|
2013-12-11 22:49:13 +08:00
|
|
|
|
2015-08-12 21:23:02 +08:00
|
|
|
#ifdef WIN32
|
2015-02-21 00:47:45 +08:00
|
|
|
#ifdef WINRT
|
2015-08-12 21:23:02 +08:00
|
|
|
static __declspec( thread ) void* tlsData = NULL; // using C++11 thread attribute for local thread data
|
|
|
|
TlsAbstraction::TlsAbstraction() {}
|
|
|
|
TlsAbstraction::~TlsAbstraction() {}
|
|
|
|
void* TlsAbstraction::GetData() const
|
|
|
|
{
|
|
|
|
return tlsData;
|
|
|
|
}
|
|
|
|
void TlsAbstraction::SetData(void *pData)
|
|
|
|
{
|
|
|
|
tlsData = pData;
|
|
|
|
}
|
|
|
|
#else //WINRT
|
|
|
|
TlsAbstraction::TlsAbstraction()
|
|
|
|
{
|
|
|
|
tlsKey = TlsAlloc();
|
|
|
|
CV_Assert(tlsKey != TLS_OUT_OF_INDEXES);
|
|
|
|
}
|
|
|
|
TlsAbstraction::~TlsAbstraction()
|
|
|
|
{
|
|
|
|
TlsFree(tlsKey);
|
|
|
|
}
|
|
|
|
void* TlsAbstraction::GetData() const
|
|
|
|
{
|
|
|
|
return TlsGetValue(tlsKey);
|
|
|
|
}
|
|
|
|
void TlsAbstraction::SetData(void *pData)
|
|
|
|
{
|
|
|
|
CV_Assert(TlsSetValue(tlsKey, pData) == TRUE);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#else // WIN32
|
|
|
|
TlsAbstraction::TlsAbstraction()
|
|
|
|
{
|
|
|
|
CV_Assert(pthread_key_create(&tlsKey, NULL) == 0);
|
|
|
|
}
|
|
|
|
TlsAbstraction::~TlsAbstraction()
|
|
|
|
{
|
|
|
|
CV_Assert(pthread_key_delete(tlsKey) == 0);
|
|
|
|
}
|
|
|
|
void* TlsAbstraction::GetData() const
|
|
|
|
{
|
|
|
|
return pthread_getspecific(tlsKey);
|
|
|
|
}
|
|
|
|
void TlsAbstraction::SetData(void *pData)
|
|
|
|
{
|
|
|
|
CV_Assert(pthread_setspecific(tlsKey, pData) == 0);
|
|
|
|
}
|
|
|
|
#endif
|
2013-12-11 22:49:13 +08:00
|
|
|
|
2015-08-12 21:23:02 +08:00
|
|
|
// Per-thread data structure
|
|
|
|
struct ThreadData
|
|
|
|
{
|
|
|
|
ThreadData()
|
2013-12-11 22:49:13 +08:00
|
|
|
{
|
2015-08-12 21:23:02 +08:00
|
|
|
idx = 0;
|
|
|
|
slots.reserve(32);
|
2013-12-11 22:49:13 +08:00
|
|
|
}
|
|
|
|
|
2015-08-12 21:23:02 +08:00
|
|
|
std::vector<void*> slots; // Data array for a thread
|
|
|
|
size_t idx; // Thread index in TLS storage. This is not OS thread ID!
|
|
|
|
};
|
2013-12-11 22:49:13 +08:00
|
|
|
|
2015-08-12 21:23:02 +08:00
|
|
|
// Main TLS storage class
|
|
|
|
class TlsStorage
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
TlsStorage()
|
2013-12-11 22:49:13 +08:00
|
|
|
{
|
2015-09-16 19:00:36 +08:00
|
|
|
tlsSlots.reserve(32);
|
2015-08-12 21:23:02 +08:00
|
|
|
threads.reserve(32);
|
2013-12-11 22:49:13 +08:00
|
|
|
}
|
2015-08-12 21:23:02 +08:00
|
|
|
~TlsStorage()
|
2013-12-11 22:49:13 +08:00
|
|
|
{
|
2015-08-12 21:23:02 +08:00
|
|
|
for(size_t i = 0; i < threads.size(); i++)
|
2013-12-11 22:49:13 +08:00
|
|
|
{
|
2015-08-12 21:23:02 +08:00
|
|
|
if(threads[i])
|
|
|
|
{
|
|
|
|
/* Current architecture doesn't allow proper global objects relase, so this check can cause crashes
|
|
|
|
|
|
|
|
// Check if all slots were properly cleared
|
|
|
|
for(size_t j = 0; j < threads[i]->slots.size(); j++)
|
|
|
|
{
|
|
|
|
CV_Assert(threads[i]->slots[j] == 0);
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
delete threads[i];
|
|
|
|
}
|
2013-12-11 22:49:13 +08:00
|
|
|
}
|
2015-08-12 21:23:02 +08:00
|
|
|
threads.clear();
|
2013-12-11 22:49:13 +08:00
|
|
|
}
|
|
|
|
|
2015-08-12 21:23:02 +08:00
|
|
|
void releaseThread()
|
2013-12-11 22:49:13 +08:00
|
|
|
{
|
2015-08-12 21:23:02 +08:00
|
|
|
AutoLock guard(mtxGlobalAccess);
|
|
|
|
ThreadData *pTD = (ThreadData*)tls.GetData();
|
|
|
|
for(size_t i = 0; i < threads.size(); i++)
|
2014-03-25 04:38:57 +08:00
|
|
|
{
|
2015-08-12 21:23:02 +08:00
|
|
|
if(pTD == threads[i])
|
|
|
|
{
|
|
|
|
threads[i] = 0;
|
|
|
|
break;
|
|
|
|
}
|
2014-03-25 04:38:57 +08:00
|
|
|
}
|
2015-08-12 21:23:02 +08:00
|
|
|
tls.SetData(0);
|
|
|
|
delete pTD;
|
2013-12-11 22:49:13 +08:00
|
|
|
}
|
|
|
|
|
2015-08-12 21:23:02 +08:00
|
|
|
// Reserve TLS storage index
|
|
|
|
size_t reserveSlot()
|
2013-12-11 22:49:13 +08:00
|
|
|
{
|
2015-08-12 21:23:02 +08:00
|
|
|
AutoLock guard(mtxGlobalAccess);
|
2015-09-16 19:00:36 +08:00
|
|
|
|
|
|
|
// Find unused slots
|
|
|
|
for(size_t slot = 0; slot < tlsSlots.size(); slot++)
|
|
|
|
{
|
|
|
|
if(!tlsSlots[slot])
|
|
|
|
{
|
|
|
|
tlsSlots[slot] = 1;
|
|
|
|
return slot;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create new slot
|
|
|
|
tlsSlots.push_back(1);
|
|
|
|
return (tlsSlots.size()-1);
|
2013-12-11 22:49:13 +08:00
|
|
|
}
|
|
|
|
|
2015-08-12 21:23:02 +08:00
|
|
|
// Release TLS storage index and pass assosiated data to caller
|
|
|
|
void releaseSlot(size_t slotIdx, std::vector<void*> &dataVec)
|
2013-12-11 22:49:13 +08:00
|
|
|
{
|
2015-08-12 21:23:02 +08:00
|
|
|
AutoLock guard(mtxGlobalAccess);
|
2015-09-16 19:00:36 +08:00
|
|
|
CV_Assert(tlsSlots.size() > slotIdx);
|
2013-12-11 22:49:13 +08:00
|
|
|
|
2015-08-12 21:23:02 +08:00
|
|
|
for(size_t i = 0; i < threads.size(); i++)
|
2013-12-11 22:49:13 +08:00
|
|
|
{
|
2016-01-14 19:38:37 +08:00
|
|
|
if(threads[i])
|
2015-08-12 21:23:02 +08:00
|
|
|
{
|
2016-01-14 19:38:37 +08:00
|
|
|
std::vector<void*>& thread_slots = threads[i]->slots;
|
|
|
|
if (thread_slots.size() > slotIdx && thread_slots[slotIdx])
|
|
|
|
{
|
|
|
|
dataVec.push_back(thread_slots[slotIdx]);
|
|
|
|
threads[i]->slots[slotIdx] = 0;
|
|
|
|
}
|
2015-08-12 21:23:02 +08:00
|
|
|
}
|
2013-12-11 22:49:13 +08:00
|
|
|
}
|
2015-09-16 19:00:36 +08:00
|
|
|
|
|
|
|
tlsSlots[slotIdx] = 0;
|
2013-12-11 22:49:13 +08:00
|
|
|
}
|
|
|
|
|
2015-08-12 21:23:02 +08:00
|
|
|
// Get data by TLS storage index
|
|
|
|
void* getData(size_t slotIdx) const
|
2013-12-11 22:49:13 +08:00
|
|
|
{
|
2015-09-16 19:00:36 +08:00
|
|
|
CV_Assert(tlsSlots.size() > slotIdx);
|
2013-12-11 22:49:13 +08:00
|
|
|
|
2015-08-12 21:23:02 +08:00
|
|
|
ThreadData* threadData = (ThreadData*)tls.GetData();
|
|
|
|
if(threadData && threadData->slots.size() > slotIdx)
|
|
|
|
return threadData->slots[slotIdx];
|
|
|
|
|
|
|
|
return NULL;
|
2013-12-11 22:49:13 +08:00
|
|
|
}
|
|
|
|
|
2015-09-16 19:00:36 +08:00
|
|
|
// Gather data from threads by TLS storage index
|
|
|
|
void gather(size_t slotIdx, std::vector<void*> &dataVec)
|
|
|
|
{
|
|
|
|
AutoLock guard(mtxGlobalAccess);
|
|
|
|
CV_Assert(tlsSlots.size() > slotIdx);
|
|
|
|
|
|
|
|
for(size_t i = 0; i < threads.size(); i++)
|
|
|
|
{
|
2016-01-14 19:38:37 +08:00
|
|
|
if(threads[i])
|
|
|
|
{
|
|
|
|
std::vector<void*>& thread_slots = threads[i]->slots;
|
|
|
|
if (thread_slots.size() > slotIdx && thread_slots[slotIdx])
|
|
|
|
dataVec.push_back(thread_slots[slotIdx]);
|
|
|
|
}
|
2015-09-16 19:00:36 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-12 21:23:02 +08:00
|
|
|
// Set data to storage index
|
|
|
|
void setData(size_t slotIdx, void* pData)
|
2013-12-11 22:49:13 +08:00
|
|
|
{
|
2015-09-16 19:00:36 +08:00
|
|
|
CV_Assert(tlsSlots.size() > slotIdx && pData != NULL);
|
2015-08-12 21:23:02 +08:00
|
|
|
|
|
|
|
ThreadData* threadData = (ThreadData*)tls.GetData();
|
|
|
|
if(!threadData)
|
2013-12-11 22:49:13 +08:00
|
|
|
{
|
2015-08-12 21:23:02 +08:00
|
|
|
threadData = new ThreadData;
|
|
|
|
tls.SetData((void*)threadData);
|
|
|
|
{
|
|
|
|
AutoLock guard(mtxGlobalAccess);
|
|
|
|
threadData->idx = threads.size();
|
|
|
|
threads.push_back(threadData);
|
|
|
|
}
|
2013-12-11 22:49:13 +08:00
|
|
|
}
|
2015-08-12 21:23:02 +08:00
|
|
|
|
|
|
|
if(slotIdx >= threadData->slots.size())
|
2015-09-16 19:00:36 +08:00
|
|
|
{
|
|
|
|
AutoLock guard(mtxGlobalAccess);
|
|
|
|
while(slotIdx >= threadData->slots.size())
|
|
|
|
threadData->slots.push_back(NULL);
|
|
|
|
}
|
2015-08-12 21:23:02 +08:00
|
|
|
threadData->slots[slotIdx] = pData;
|
2013-12-11 22:49:13 +08:00
|
|
|
}
|
2015-08-12 21:23:02 +08:00
|
|
|
|
|
|
|
private:
|
|
|
|
TlsAbstraction tls; // TLS abstraction layer instance
|
|
|
|
|
|
|
|
Mutex mtxGlobalAccess; // Shared objects operation guard
|
2015-09-16 19:00:36 +08:00
|
|
|
std::vector<int> tlsSlots; // TLS keys state
|
2015-08-12 21:23:02 +08:00
|
|
|
std::vector<ThreadData*> threads; // Array for all allocated data. Thread data pointers are placed here to allow data cleanup
|
2013-12-11 22:49:13 +08:00
|
|
|
};
|
2014-01-19 07:39:50 +08:00
|
|
|
|
2015-08-12 21:23:02 +08:00
|
|
|
// Create global TLS storage object
|
|
|
|
static TlsStorage &getTlsStorage()
|
2014-01-19 07:39:50 +08:00
|
|
|
{
|
2015-08-12 21:23:02 +08:00
|
|
|
CV_SINGLETON_LAZY_INIT_REF(TlsStorage, new TlsStorage())
|
2014-01-19 07:39:50 +08:00
|
|
|
}
|
2013-12-11 22:49:13 +08:00
|
|
|
|
|
|
|
TLSDataContainer::TLSDataContainer()
|
|
|
|
{
|
2015-08-12 21:23:02 +08:00
|
|
|
key_ = (int)getTlsStorage().reserveSlot(); // Reserve key from TLS storage
|
2012-08-17 21:32:06 +08:00
|
|
|
}
|
|
|
|
|
2013-12-11 22:49:13 +08:00
|
|
|
TLSDataContainer::~TLSDataContainer()
|
|
|
|
{
|
2015-08-12 21:23:02 +08:00
|
|
|
CV_Assert(key_ == -1); // Key must be released in child object
|
2013-12-11 22:49:13 +08:00
|
|
|
}
|
|
|
|
|
2015-09-16 19:00:36 +08:00
|
|
|
void TLSDataContainer::gatherData(std::vector<void*> &data) const
|
|
|
|
{
|
|
|
|
getTlsStorage().gather(key_, data);
|
|
|
|
}
|
|
|
|
|
2015-08-12 21:23:02 +08:00
|
|
|
void TLSDataContainer::release()
|
2013-12-11 22:49:13 +08:00
|
|
|
{
|
2015-08-12 21:23:02 +08:00
|
|
|
std::vector<void*> data;
|
|
|
|
data.reserve(32);
|
|
|
|
getTlsStorage().releaseSlot(key_, data); // Release key and get stored data for proper destruction
|
|
|
|
for(size_t i = 0; i < data.size(); i++) // Delete all assosiated data
|
|
|
|
deleteDataInstance(data[i]);
|
|
|
|
key_ = -1;
|
2013-12-11 22:49:13 +08:00
|
|
|
}
|
|
|
|
|
2015-08-12 21:23:02 +08:00
|
|
|
void* TLSDataContainer::getData() const
|
2013-12-11 22:49:13 +08:00
|
|
|
{
|
2015-08-12 21:23:02 +08:00
|
|
|
void* pData = getTlsStorage().getData(key_); // Check if data was already allocated
|
|
|
|
if(!pData)
|
2013-12-11 22:49:13 +08:00
|
|
|
{
|
2015-08-12 21:23:02 +08:00
|
|
|
// Create new data instance and save it to TLS storage
|
|
|
|
pData = createDataInstance();
|
|
|
|
getTlsStorage().setData(key_, pData);
|
2013-12-11 22:49:13 +08:00
|
|
|
}
|
2015-08-12 21:23:02 +08:00
|
|
|
return pData;
|
2013-12-11 22:49:13 +08:00
|
|
|
}
|
|
|
|
|
2015-02-04 18:03:27 +08:00
|
|
|
TLSData<CoreTLSData>& getCoreTlsData()
|
|
|
|
{
|
2015-06-23 19:31:01 +08:00
|
|
|
CV_SINGLETON_LAZY_INIT_REF(TLSData<CoreTLSData>, new TLSData<CoreTLSData>())
|
2015-02-04 18:03:27 +08:00
|
|
|
}
|
|
|
|
|
2015-08-12 21:23:02 +08:00
|
|
|
#if defined CVAPI_EXPORTS && defined WIN32 && !defined WINCE
|
|
|
|
#ifdef WINRT
|
|
|
|
#pragma warning(disable:4447) // Disable warning 'main' signature found without threading model
|
|
|
|
#endif
|
|
|
|
|
2015-09-01 05:59:08 +08:00
|
|
|
extern "C"
|
|
|
|
BOOL WINAPI DllMain(HINSTANCE, DWORD fdwReason, LPVOID lpReserved);
|
|
|
|
|
2015-08-12 21:23:02 +08:00
|
|
|
extern "C"
|
|
|
|
BOOL WINAPI DllMain(HINSTANCE, DWORD fdwReason, LPVOID lpReserved)
|
|
|
|
{
|
|
|
|
if (fdwReason == DLL_THREAD_DETACH || fdwReason == DLL_PROCESS_DETACH)
|
|
|
|
{
|
|
|
|
if (lpReserved != NULL) // called after ExitProcess() call
|
|
|
|
{
|
|
|
|
cv::__termination = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Not allowed to free resources if lpReserved is non-null
|
|
|
|
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms682583.aspx
|
|
|
|
cv::deleteThreadAllocData();
|
|
|
|
cv::getTlsStorage().releaseThread();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
#endif
|
2015-02-04 18:03:27 +08:00
|
|
|
|
2014-10-03 19:17:28 +08:00
|
|
|
#ifdef CV_COLLECT_IMPL_DATA
|
2015-03-12 22:58:03 +08:00
|
|
|
ImplCollector& getImplData()
|
|
|
|
{
|
2015-06-23 19:31:01 +08:00
|
|
|
CV_SINGLETON_LAZY_INIT_REF(ImplCollector, new ImplCollector())
|
2015-03-12 22:58:03 +08:00
|
|
|
}
|
|
|
|
|
2014-10-03 19:17:28 +08:00
|
|
|
void setImpl(int flags)
|
|
|
|
{
|
2015-03-12 22:58:03 +08:00
|
|
|
cv::AutoLock lock(getImplData().mutex);
|
|
|
|
|
|
|
|
getImplData().implFlags = flags;
|
|
|
|
getImplData().implCode.clear();
|
|
|
|
getImplData().implFun.clear();
|
2014-10-03 19:17:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void addImpl(int flag, const char* func)
|
|
|
|
{
|
2015-03-12 22:58:03 +08:00
|
|
|
cv::AutoLock lock(getImplData().mutex);
|
|
|
|
|
|
|
|
getImplData().implFlags |= flag;
|
2014-10-03 19:17:28 +08:00
|
|
|
if(func) // use lazy collection if name was not specified
|
|
|
|
{
|
2015-03-12 22:58:03 +08:00
|
|
|
size_t index = getImplData().implCode.size();
|
|
|
|
if(!index || (getImplData().implCode[index-1] != flag || getImplData().implFun[index-1].compare(func))) // avoid duplicates
|
2014-10-03 19:17:28 +08:00
|
|
|
{
|
2015-03-12 22:58:03 +08:00
|
|
|
getImplData().implCode.push_back(flag);
|
|
|
|
getImplData().implFun.push_back(func);
|
2014-10-03 19:17:28 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int getImpl(std::vector<int> &impl, std::vector<String> &funName)
|
|
|
|
{
|
2015-03-12 22:58:03 +08:00
|
|
|
cv::AutoLock lock(getImplData().mutex);
|
|
|
|
|
|
|
|
impl = getImplData().implCode;
|
|
|
|
funName = getImplData().implFun;
|
|
|
|
return getImplData().implFlags; // return actual flags for lazy collection
|
2014-10-03 19:17:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool useCollection()
|
|
|
|
{
|
2015-03-12 22:58:03 +08:00
|
|
|
return getImplData().useCollection;
|
2014-10-03 19:17:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void setUseCollection(bool flag)
|
|
|
|
{
|
2015-03-12 22:58:03 +08:00
|
|
|
cv::AutoLock lock(getImplData().mutex);
|
|
|
|
|
|
|
|
getImplData().useCollection = flag;
|
2014-10-03 19:17:28 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-08-15 22:12:45 +08:00
|
|
|
namespace instr
|
|
|
|
{
|
|
|
|
bool useInstrumentation()
|
|
|
|
{
|
|
|
|
#ifdef ENABLE_INSTRUMENTATION
|
|
|
|
return getInstrumentStruct().useInstr;
|
|
|
|
#else
|
|
|
|
return false;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void setUseInstrumentation(bool flag)
|
|
|
|
{
|
|
|
|
#ifdef ENABLE_INSTRUMENTATION
|
|
|
|
getInstrumentStruct().useInstr = flag;
|
|
|
|
#else
|
|
|
|
CV_UNUSED(flag);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
InstrNode* getTrace()
|
|
|
|
{
|
|
|
|
#ifdef ENABLE_INSTRUMENTATION
|
|
|
|
return &getInstrumentStruct().rootNode;
|
|
|
|
#else
|
|
|
|
return NULL;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void resetTrace()
|
|
|
|
{
|
|
|
|
#ifdef ENABLE_INSTRUMENTATION
|
|
|
|
getInstrumentStruct().rootNode.removeChilds();
|
|
|
|
getInstrumentTLSStruct().pCurrentNode = &getInstrumentStruct().rootNode;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void setFlags(int modeFlags)
|
|
|
|
{
|
|
|
|
#ifdef ENABLE_INSTRUMENTATION
|
|
|
|
getInstrumentStruct().enableMapping = (modeFlags & FLAGS_MAPPING);
|
|
|
|
#else
|
|
|
|
CV_UNUSED(modeFlags);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
int getFlags()
|
|
|
|
{
|
|
|
|
#ifdef ENABLE_INSTRUMENTATION
|
|
|
|
int flags = 0;
|
|
|
|
if(getInstrumentStruct().enableMapping)
|
|
|
|
flags |= FLAGS_MAPPING;
|
|
|
|
return flags;
|
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
NodeData::NodeData(const char* funName, const char* fileName, int lineNum, int instrType, int implType)
|
|
|
|
{
|
|
|
|
m_instrType = TYPE_GENERAL;
|
|
|
|
m_implType = IMPL_PLAIN;
|
|
|
|
|
|
|
|
m_funError = false;
|
|
|
|
m_counter = 0;
|
|
|
|
m_stopPoint = false;
|
|
|
|
m_ticksMean = 0;
|
|
|
|
|
|
|
|
m_funName = funName;
|
|
|
|
m_instrType = instrType;
|
|
|
|
m_implType = implType;
|
|
|
|
m_fileName = fileName;
|
|
|
|
m_lineNum = lineNum;
|
|
|
|
}
|
|
|
|
NodeData::NodeData(NodeData &ref)
|
|
|
|
{
|
|
|
|
*this = ref;
|
|
|
|
}
|
|
|
|
NodeData& NodeData::operator=(const NodeData &right)
|
|
|
|
{
|
|
|
|
this->m_funName = right.m_funName;
|
|
|
|
this->m_instrType = right.m_instrType;
|
|
|
|
this->m_implType = right.m_implType;
|
|
|
|
this->m_funError = right.m_funError;
|
|
|
|
this->m_counter = right.m_counter;
|
|
|
|
this->m_stopPoint = right.m_stopPoint;
|
|
|
|
this->m_ticksMean = right.m_ticksMean;
|
|
|
|
this->m_fileName = right.m_fileName;
|
|
|
|
this->m_lineNum = right.m_lineNum;
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
NodeData::~NodeData()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
bool operator==(const NodeData& left, const NodeData& right)
|
|
|
|
{
|
|
|
|
if(left.m_lineNum == right.m_lineNum && left.m_funName == right.m_funName && left.m_fileName == right.m_fileName)
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef ENABLE_INSTRUMENTATION
|
|
|
|
InstrStruct& getInstrumentStruct()
|
|
|
|
{
|
|
|
|
static InstrStruct instr;
|
|
|
|
return instr;
|
|
|
|
}
|
|
|
|
|
|
|
|
InstrTLSStruct& getInstrumentTLSStruct()
|
|
|
|
{
|
|
|
|
return *getInstrumentStruct().tlsStruct.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
InstrNode* getCurrentNode()
|
|
|
|
{
|
|
|
|
return getInstrumentTLSStruct().pCurrentNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
IntrumentationRegion::IntrumentationRegion(const char* funName, const char* fileName, int lineNum, int instrType, int implType)
|
|
|
|
{
|
|
|
|
m_disabled = false;
|
|
|
|
m_regionTicks = 0;
|
|
|
|
|
|
|
|
InstrStruct *pStruct = &getInstrumentStruct();
|
|
|
|
if(pStruct->useInstr)
|
|
|
|
{
|
|
|
|
InstrTLSStruct *pTLS = &getInstrumentTLSStruct();
|
|
|
|
|
|
|
|
// Disable in case of failure
|
|
|
|
if(!pTLS->pCurrentNode)
|
|
|
|
{
|
|
|
|
m_disabled = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_disabled = pTLS->pCurrentNode->m_payload.m_stopPoint;
|
|
|
|
if(m_disabled)
|
|
|
|
return;
|
|
|
|
|
|
|
|
NodeData payload(funName, fileName, lineNum, instrType, implType);
|
|
|
|
Node<NodeData>* pChild = NULL;
|
|
|
|
|
|
|
|
if(pStruct->enableMapping)
|
|
|
|
{
|
|
|
|
// Critical section
|
|
|
|
cv::AutoLock guard(pStruct->mutexCreate); // Guard from concurrent child creation
|
|
|
|
pChild = pTLS->pCurrentNode->findChild(payload);
|
|
|
|
if(!pChild)
|
|
|
|
{
|
|
|
|
pChild = new Node<NodeData>(payload);
|
|
|
|
pTLS->pCurrentNode->addChild(pChild);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pChild = pTLS->pCurrentNode->findChild(payload);
|
|
|
|
if(!pChild)
|
|
|
|
{
|
|
|
|
pTLS->pCurrentNode->m_payload.m_stopPoint = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pTLS->pCurrentNode = pChild;
|
|
|
|
|
|
|
|
m_regionTicks = getTickCount();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
IntrumentationRegion::~IntrumentationRegion()
|
|
|
|
{
|
|
|
|
InstrStruct *pStruct = &getInstrumentStruct();
|
|
|
|
if(pStruct->useInstr)
|
|
|
|
{
|
|
|
|
if(!m_disabled)
|
|
|
|
{
|
|
|
|
InstrTLSStruct *pTLS = &getInstrumentTLSStruct();
|
|
|
|
if(pTLS->pCurrentNode->m_payload.m_stopPoint)
|
|
|
|
{
|
|
|
|
pTLS->pCurrentNode->m_payload.m_stopPoint = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(pTLS->pCurrentNode->m_payload.m_implType == cv::instr::IMPL_OPENCL &&
|
|
|
|
pTLS->pCurrentNode->m_payload.m_instrType == cv::instr::TYPE_FUN)
|
|
|
|
cv::ocl::finish();
|
|
|
|
|
|
|
|
uint64 ticks = (getTickCount() - m_regionTicks);
|
|
|
|
{
|
|
|
|
cv::AutoLock guard(pStruct->mutexCount); // Concurrent ticks accumulation
|
|
|
|
pTLS->pCurrentNode->m_payload.m_counter++;
|
|
|
|
if(pTLS->pCurrentNode->m_payload.m_counter <= 1)
|
|
|
|
pTLS->pCurrentNode->m_payload.m_ticksMean = ticks;
|
|
|
|
else
|
|
|
|
pTLS->pCurrentNode->m_payload.m_ticksMean = (pTLS->pCurrentNode->m_payload.m_ticksMean*(pTLS->pCurrentNode->m_payload.m_counter-1) + ticks)/pTLS->pCurrentNode->m_payload.m_counter;
|
|
|
|
}
|
|
|
|
|
|
|
|
pTLS->pCurrentNode = pTLS->pCurrentNode->m_pParent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2014-04-17 19:21:30 +08:00
|
|
|
namespace ipp
|
|
|
|
{
|
|
|
|
|
2016-08-12 14:50:42 +08:00
|
|
|
struct IPPInitSingleton
|
2015-09-25 23:00:53 +08:00
|
|
|
{
|
|
|
|
public:
|
2016-08-12 14:50:42 +08:00
|
|
|
IPPInitSingleton()
|
2015-09-25 23:00:53 +08:00
|
|
|
{
|
|
|
|
useIPP = true;
|
|
|
|
ippStatus = 0;
|
|
|
|
funcname = NULL;
|
|
|
|
filename = NULL;
|
|
|
|
linen = 0;
|
|
|
|
ippFeatures = 0;
|
|
|
|
|
|
|
|
#ifdef HAVE_IPP
|
|
|
|
const char* pIppEnv = getenv("OPENCV_IPP");
|
|
|
|
cv::String env = pIppEnv;
|
|
|
|
if(env.size())
|
|
|
|
{
|
|
|
|
if(env == "disabled")
|
|
|
|
{
|
|
|
|
std::cerr << "WARNING: IPP was disabled by OPENCV_IPP environment variable" << std::endl;
|
|
|
|
useIPP = false;
|
|
|
|
}
|
|
|
|
#if IPP_VERSION_X100 >= 900
|
|
|
|
else if(env == "sse")
|
|
|
|
ippFeatures = ippCPUID_SSE;
|
|
|
|
else if(env == "sse2")
|
|
|
|
ippFeatures = ippCPUID_SSE2;
|
2015-10-12 15:51:28 +08:00
|
|
|
else if(env == "sse3")
|
|
|
|
ippFeatures = ippCPUID_SSE3;
|
|
|
|
else if(env == "ssse3")
|
|
|
|
ippFeatures = ippCPUID_SSSE3;
|
|
|
|
else if(env == "sse41")
|
|
|
|
ippFeatures = ippCPUID_SSE41;
|
2015-09-25 23:00:53 +08:00
|
|
|
else if(env == "sse42")
|
|
|
|
ippFeatures = ippCPUID_SSE42;
|
|
|
|
else if(env == "avx")
|
|
|
|
ippFeatures = ippCPUID_AVX;
|
|
|
|
else if(env == "avx2")
|
|
|
|
ippFeatures = ippCPUID_AVX2;
|
|
|
|
#endif
|
|
|
|
else
|
|
|
|
std::cerr << "ERROR: Improper value of OPENCV_IPP: " << env.c_str() << std::endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
IPP_INITIALIZER(ippFeatures)
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
bool useIPP;
|
|
|
|
|
|
|
|
int ippStatus; // 0 - all is ok, -1 - IPP functions failed
|
|
|
|
const char *funcname;
|
|
|
|
const char *filename;
|
|
|
|
int linen;
|
|
|
|
int ippFeatures;
|
|
|
|
};
|
|
|
|
|
2016-08-12 14:50:42 +08:00
|
|
|
static IPPInitSingleton& getIPPSingleton()
|
2015-09-25 23:00:53 +08:00
|
|
|
{
|
2016-08-12 14:50:42 +08:00
|
|
|
CV_SINGLETON_LAZY_INIT_REF(IPPInitSingleton, new IPPInitSingleton())
|
2015-09-25 23:00:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int getIppFeatures()
|
|
|
|
{
|
|
|
|
#ifdef HAVE_IPP
|
2016-08-12 14:50:42 +08:00
|
|
|
return getIPPSingleton().ippFeatures;
|
2015-09-25 23:00:53 +08:00
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
2014-04-16 22:50:23 +08:00
|
|
|
|
|
|
|
void setIppStatus(int status, const char * const _funcname, const char * const _filename, int _line)
|
2014-04-16 19:34:18 +08:00
|
|
|
{
|
2016-08-12 14:50:42 +08:00
|
|
|
getIPPSingleton().ippStatus = status;
|
|
|
|
getIPPSingleton().funcname = _funcname;
|
|
|
|
getIPPSingleton().filename = _filename;
|
|
|
|
getIPPSingleton().linen = _line;
|
2014-04-16 19:34:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int getIppStatus()
|
|
|
|
{
|
2016-08-12 14:50:42 +08:00
|
|
|
return getIPPSingleton().ippStatus;
|
2014-04-16 22:50:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
String getIppErrorLocation()
|
|
|
|
{
|
2016-08-12 14:50:42 +08:00
|
|
|
return format("%s:%d %s", getIPPSingleton().filename ? getIPPSingleton().filename : "", getIPPSingleton().linen, getIPPSingleton().funcname ? getIPPSingleton().funcname : "");
|
2014-04-16 19:34:18 +08:00
|
|
|
}
|
|
|
|
|
2014-10-03 19:17:28 +08:00
|
|
|
bool useIPP()
|
|
|
|
{
|
|
|
|
#ifdef HAVE_IPP
|
2015-02-04 18:03:27 +08:00
|
|
|
CoreTLSData* data = getCoreTlsData().get();
|
2014-10-03 19:17:28 +08:00
|
|
|
if(data->useIPP < 0)
|
|
|
|
{
|
2016-08-12 14:50:42 +08:00
|
|
|
data->useIPP = getIPPSingleton().useIPP;
|
2014-10-03 19:17:28 +08:00
|
|
|
}
|
|
|
|
return (data->useIPP > 0);
|
|
|
|
#else
|
|
|
|
return false;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void setUseIPP(bool flag)
|
|
|
|
{
|
2015-02-04 18:03:27 +08:00
|
|
|
CoreTLSData* data = getCoreTlsData().get();
|
2014-10-03 19:17:28 +08:00
|
|
|
#ifdef HAVE_IPP
|
2016-08-12 14:50:42 +08:00
|
|
|
data->useIPP = (getIPPSingleton().useIPP)?flag:false;
|
2014-10-03 19:17:28 +08:00
|
|
|
#else
|
|
|
|
(void)flag;
|
|
|
|
data->useIPP = false;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2014-04-17 19:21:30 +08:00
|
|
|
} // namespace ipp
|
|
|
|
|
2015-02-27 17:52:11 +08:00
|
|
|
} // namespace cv
|
|
|
|
|
2015-02-27 00:34:20 +08:00
|
|
|
#ifdef HAVE_TEGRA_OPTIMIZATION
|
|
|
|
|
|
|
|
namespace tegra {
|
|
|
|
|
|
|
|
bool useTegra()
|
|
|
|
{
|
2015-02-27 17:52:11 +08:00
|
|
|
cv::CoreTLSData* data = cv::getCoreTlsData().get();
|
2015-02-27 00:34:20 +08:00
|
|
|
|
|
|
|
if (data->useTegra < 0)
|
|
|
|
{
|
|
|
|
const char* pTegraEnv = getenv("OPENCV_TEGRA");
|
|
|
|
if (pTegraEnv && (cv::String(pTegraEnv) == "disabled"))
|
|
|
|
data->useTegra = false;
|
|
|
|
else
|
|
|
|
data->useTegra = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (data->useTegra > 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void setUseTegra(bool flag)
|
|
|
|
{
|
2015-02-27 17:52:11 +08:00
|
|
|
cv::CoreTLSData* data = cv::getCoreTlsData().get();
|
2015-02-27 00:34:20 +08:00
|
|
|
data->useTegra = flag;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace tegra
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2013-07-10 21:43:46 +08:00
|
|
|
/* End of file. */
|