/*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.
//
//
// Intel License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// 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 Intel Corporation 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*/
/****************************************************************************************/
/* Dynamic detection and loading of IPP modules */
/****************************************************************************************/
#include "_cxcore.h"
#if defined _MSC_VER && _MSC_VER >= 1200
#pragma warning( disable: 4115 ) /* type definition in () */
#endif
#if defined _MSC_VER && defined WIN64 && !defined EM64T
#pragma optimize( "", off )
#endif
#if defined WIN32 || defined WIN64
#include <windows.h>
#else
#include <dlfcn.h>
#include <sys/time.h>
#endif
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#define CV_PROC_GENERIC 0
#define CV_PROC_SHIFT 10
#define CV_PROC_ARCH_MASK ((1 << CV_PROC_SHIFT) - 1)
#define CV_PROC_IA32_GENERIC 1
#define CV_PROC_IA32_WITH_MMX (CV_PROC_IA32_GENERIC|(2 << CV_PROC_SHIFT))
#define CV_PROC_IA32_WITH_SSE (CV_PROC_IA32_GENERIC|(3 << CV_PROC_SHIFT))
#define CV_PROC_IA32_WITH_SSE2 (CV_PROC_IA32_GENERIC|(4 << CV_PROC_SHIFT))
#define CV_PROC_IA64 2
#define CV_PROC_EM64T 3
#define CV_GET_PROC_ARCH(model) ((model) & CV_PROC_ARCH_MASK)
typedef struct CvProcessorInfo
{
int model;
int count;
double frequency; // clocks per microsecond
}
CvProcessorInfo;
#undef MASM_INLINE_ASSEMBLY
#if defined WIN32 && !defined WIN64
#if defined _MSC_VER
#define MASM_INLINE_ASSEMBLY 1
#elif defined __BORLANDC__
#if __BORLANDC__ >= 0x560
#define MASM_INLINE_ASSEMBLY 1
#endif
#endif
#endif
/*
determine processor type
*/
static void
icvInitProcessorInfo( CvProcessorInfo* cpu_info )
{
memset( cpu_info, 0, sizeof(*cpu_info) );
cpu_info->model = CV_PROC_GENERIC;
#if defined WIN32 || defined WIN64
#ifndef PROCESSOR_ARCHITECTURE_AMD64
#define PROCESSOR_ARCHITECTURE_AMD64 9
#endif
#ifndef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64
#define PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 10
#endif
SYSTEM_INFO sys;
LARGE_INTEGER freq;
GetSystemInfo( &sys );
if( sys.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL &&
sys.dwProcessorType == PROCESSOR_INTEL_PENTIUM && sys.wProcessorLevel >= 6 )
{
int version = 0, features = 0, family = 0;
int id = 0;
HKEY key = 0;
cpu_info->count = (int)sys.dwNumberOfProcessors;
unsigned long val = 0, sz = sizeof(val);
if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\SYSTEM\\CentralProcessor\\0\\",
0, KEY_QUERY_VALUE, &key ) >= 0 )
{
if( RegQueryValueEx( key, "~MHz", 0, 0, (uchar*)&val, &sz ) >= 0 )
cpu_info->frequency = (double)val;
RegCloseKey( key );
}
#ifdef MASM_INLINE_ASSEMBLY
__asm
{
/* use CPUID to determine the features supported */
pushfd
mov eax, 1
push ebx
push esi
push edi
#ifdef __BORLANDC__
db 0fh
db 0a2h
#else
_emit 0x0f
_emit 0xa2
#endif
pop edi
pop esi
pop ebx
mov version, eax
mov features, edx
popfd
}
#elif defined WIN32 && __GNUC__ > 2
asm volatile
(
"movl $1,%%eax\n\t"
".byte 0x0f; .byte 0xa2\n\t"
"movl %%eax, %0\n\t"
"movl %%edx, %1\n\t"
: "=r"(version), "=r" (features)
:
: "%ebx", "%esi", "%edi"
);
#else
{
static const char cpuid_code[] =
"\x53\x56\x57\xb8\x01\x00\x00\x00\x0f\xa2\x5f\x5e\x5b\xc3";
typedef int64 (CV_CDECL * func_ptr)(void);
func_ptr cpuid = (func_ptr)(void*)cpuid_code;
int64 cpuid_val = cpuid();
version = (int)cpuid_val;
features = (int)(cpuid_val >> 32);
}
#endif
#define ICV_CPUID_M6 ((1<<15)|(1<<23)) /* cmov + MMX */
#define ICV_CPUID_A6 ((1<<25)|ICV_CPUID_M6) /* <all above> + SSE */
#define ICV_CPUID_W7 ((1<<26)|ICV_CPUID_A6) /* <all above> + SSE2 */
family = (version >> 8) & 15;
if( family >= 6 && (features & ICV_CPUID_M6) != 0 ) /* Pentium II or higher */
id = features & ICV_CPUID_W7;
cpu_info->model = id == ICV_CPUID_W7 ? CV_PROC_IA32_WITH_SSE2 :
id == ICV_CPUID_A6 ? CV_PROC_IA32_WITH_SSE :
id == ICV_CPUID_M6 ? CV_PROC_IA32_WITH_MMX :
CV_PROC_IA32_GENERIC;
}
else
{
#if defined EM64T
if( sys.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 )
cpu_info->model = CV_PROC_EM64T;
#elif defined WIN64
if( sys.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64 )
cpu_info->model = CV_PROC_IA64;
#endif
if( QueryPerformanceFrequency( &freq ) )
cpu_info->frequency = (double)freq.QuadPart;
}
#else
cpu_info->frequency = 1;
#ifdef __x86_64__
cpu_info->model = CV_PROC_EM64T;
#elif defined __ia64__
cpu_info->model = CV_PROC_IA64;
#elif !defined __i386__
cpu_info->model = CV_PROC_GENERIC;
#else
cpu_info->model = CV_PROC_IA32_GENERIC;
// reading /proc/cpuinfo file (proc file system must be supported)
FILE *file = fopen( "/proc/cpuinfo", "r" );
if( file )
{
char buffer[1024];
int max_size = sizeof(buffer)-1;
for(;;)
{
const char* ptr = fgets( buffer, max_size, file );
if( !ptr )
break;
if( strncmp( buffer, "flags", 5 ) == 0 )
{
if( strstr( buffer, "mmx" ) && strstr( buffer, "cmov" ))
{
cpu_info->model = CV_PROC_IA32_WITH_MMX;
if( strstr( buffer, "xmm" ) || strstr( buffer, "sse" ))
{
cpu_info->model = CV_PROC_IA32_WITH_SSE;
if( strstr( buffer, "emm" ))
cpu_info->model = CV_PROC_IA32_WITH_SSE2;
}
}
}
else if( strncmp( buffer, "cpu MHz", 7 ) == 0 )
{
char* pos = strchr( buffer, ':' );
if( pos )
cpu_info->frequency = strtod( pos + 1, &pos );
}
}
fclose( file );
if( CV_GET_PROC_ARCH(cpu_info->model) != CV_PROC_IA32_GENERIC )
cpu_info->frequency = 1;
else
assert( cpu_info->frequency > 1 );
}
#endif
#endif
}
CV_INLINE const CvProcessorInfo*
icvGetProcessorInfo()
{
static CvProcessorInfo cpu_info;
static int init_cpu_info = 0;
if( !init_cpu_info )
{
icvInitProcessorInfo( &cpu_info );
init_cpu_info = 1;
}
return &cpu_info;
}
/****************************************************************************************/
/* Make functions descriptions */
/****************************************************************************************/
#undef IPCVAPI_EX
#define IPCVAPI_EX(type,func_name,names,modules,arg) \
{ (void**)&func_name##_p, (void*)(size_t)-1, names, modules, 0 },
#undef IPCVAPI_C_EX
#define IPCVAPI_C_EX(type,func_name,names,modules,arg) \
{ (void**)&func_name##_p, (void*)(size_t)-1, names, modules, 0 },
static CvPluginFuncInfo cxcore_ipp_tab[] =
{
#undef _CXCORE_IPP_H_
#include "_cxipp.h"
#undef _CXCORE_IPP_H_
{0, 0, 0, 0, 0}
};
/*
determine processor type, load appropriate dll and
initialize all function pointers
*/
#if defined WIN32 || defined WIN64
#define DLL_PREFIX ""
#define DLL_SUFFIX ".dll"
#else
#define DLL_PREFIX "lib"
#define DLL_SUFFIX ".so"
#define LoadLibrary(name) dlopen(name, RTLD_LAZY)
#define FreeLibrary(name) dlclose(name)
#define GetProcAddress dlsym
typedef void* HMODULE;
#endif
#if 0 /*def _DEBUG*/
#define DLL_DEBUG_FLAG "d"
#else
#define DLL_DEBUG_FLAG ""
#endif
#define VERBOSE_LOADING 0
#if VERBOSE_LOADING
#define ICV_PRINTF(args) printf args; fflush(stdout)
#else
#define ICV_PRINTF(args)
#endif
typedef struct CvPluginInfo
{
const char* basename;
HMODULE handle;
char name[100];
}
CvPluginInfo;
static CvPluginInfo plugins[CV_PLUGIN_MAX];
static CvModuleInfo cxcore_info = { 0, "cxcore", CV_VERSION, cxcore_ipp_tab };
CvModuleInfo *CvModule::first = 0, *CvModule::last = 0;
CvModule::CvModule( CvModuleInfo* _info )
{
cvRegisterModule( _info );
info = last;
}
CvModule::~CvModule()
{
if( info )
{
CvModuleInfo* p = first;
for( ; p != 0 && p->next != info; p = p->next )
;
if( p )
p->next = info->next;
if( first == info )
first = info->next;
if( last == info )
last = p;
cvFree( &info );
info = 0;
}
}
static int
icvUpdatePluginFuncTab( CvPluginFuncInfo* func_tab )
{
int i, loaded_functions = 0;
// 1. reset pointers
for( i = 0; func_tab[i].func_addr != 0; i++ )
{
if( func_tab[i].default_func_addr == (void*)(size_t)-1 )
func_tab[i].default_func_addr = *func_tab[i].func_addr;
else
*func_tab[i].func_addr = func_tab[i].default_func_addr;
func_tab[i].loaded_from = 0;
}
// ippopencv substitutes all the other IPP modules
if( plugins[CV_PLUGIN_OPTCV].handle != 0 )
{
for( i = 2; i < CV_PLUGIN_MKL; i++ )
{
assert( plugins[i].handle == 0 );
plugins[i].handle = plugins[CV_PLUGIN_OPTCV].handle;
}
}
// 2. try to find corresponding functions in ipp* and reassign pointers to them
for( i = 0; func_tab[i].func_addr != 0; i++ )
{
#if defined _MSC_VER && _MSC_VER >= 1200
#pragma warning( disable: 4054 4055 ) /* converting pointers to code<->data */
#endif
char name[100];
int j = 0, idx = 0;
assert( func_tab[i].loaded_from == 0 );
if( func_tab[i].search_modules )
{
uchar* addr = 0;
const char* name_ptr = func_tab[i].func_names;
for( ; j < 10 && name_ptr; j++ )
{
const char* name_start = name_ptr;
const char* name_end;
while( !isalpha(name_start[0]) && name_start[0] != '\0' )
name_start++;
if( !name_start[0] )
name_start = 0;
name_end = name_start ? strchr( name_start, ',' ) : 0;
idx = (func_tab[i].search_modules / (1<<j*4)) % CV_PLUGIN_MAX;
if( plugins[idx].handle != 0 && name_start )
{
if( name_end != 0 )
{
strncpy( name, name_start, name_end - name_start );
name[name_end - name_start] = '\0';
}
else
strcpy( name, name_start );
addr = (uchar*)GetProcAddress( plugins[idx].handle, name );
if( addr )
break;
}
name_ptr = name_end;
}
if( addr )
{
/*#ifdef WIN32
while( *addr == 0xE9 )
addr += 5 + *((int*)(addr + 1));
#endif*/
*func_tab[i].func_addr = addr;
func_tab[i].loaded_from = idx; // store index of the module
// that contain the loaded function
loaded_functions++;
ICV_PRINTF(("%s: \t%s\n", name, plugins[idx].name ));
}
#if defined _MSC_VER && _MSC_VER >= 1200
#pragma warning( default: 4054 4055 )
#endif
}
}
#if VERBOSE_LOADING
{
int not_loaded = 0;
ICV_PRINTF(("\nTotal loaded: %d\n\n", loaded_functions ));
printf( "***************************************************\nNot loaded ...\n\n" );
for( i = 0; func_tab[i].func_addr != 0; i++ )
if( !func_tab[i].loaded_from )
{
ICV_PRINTF(( "%s\n", func_tab[i].func_names ));
not_loaded++;
}
ICV_PRINTF(("\nTotal: %d\n", not_loaded ));
}
#endif
if( plugins[CV_PLUGIN_OPTCV].handle != 0 )
{
for( i = 2; i < CV_PLUGIN_MKL; i++ )
plugins[i].handle = 0;
}
return loaded_functions;
}
CV_IMPL int
cvRegisterModule( const CvModuleInfo* module )
{
CvModuleInfo* module_copy = 0;
CV_FUNCNAME( "cvRegisterModule" );
__BEGIN__;
size_t name_len, version_len;
CV_ASSERT( module != 0 && module->name != 0 && module->version != 0 );
name_len = strlen(module->name);
version_len = strlen(module->version);
CV_CALL( module_copy = (CvModuleInfo*)cvAlloc( sizeof(*module_copy) +
name_len + 1 + version_len + 1 ));
*module_copy = *module;
module_copy->name = (char*)(module_copy + 1);
module_copy->version = (char*)(module_copy + 1) + name_len + 1;
memcpy( (void*)module_copy->name, module->name, name_len + 1 );
memcpy( (void*)module_copy->version, module->version, version_len + 1 );
module_copy->next = 0;
if( CvModule::first == 0 )
CvModule::first = module_copy;
else
CvModule::last->next = module_copy;
CvModule::last = module_copy;
if( CvModule::first == CvModule::last )
{
CV_CALL( cvUseOptimized(1));
}
else
{
CV_CALL( icvUpdatePluginFuncTab( module_copy->func_tab ));
}
__END__;
if( cvGetErrStatus() < 0 && module_copy )
cvFree( &module_copy );
return module_copy ? 0 : -1;
}
CV_IMPL int
cvUseOptimized( int load_flag )
{
int i, loaded_modules = 0, loaded_functions = 0;
CvModuleInfo* module;
const CvProcessorInfo* cpu_info = icvGetProcessorInfo();
int arch = CV_GET_PROC_ARCH(cpu_info->model);
// TODO: implement some more elegant way
// to find the latest and the greatest IPP/MKL libraries
static const char* opencv_sfx[] = { "100", "099", "097", 0 };
static const char* ipp_sfx_ia32[] = { "-6.1", "-6.0", "-5.3", "-5.2", "-5.1", "", 0 };
static const char* ipp_sfx_ia64[] = { "64-6.1", "64-6.0", "64-5.3", "64-5.2", "64-5.1", "64", 0 };
static const char* ipp_sfx_em64t[] = { "em64t-6.1", "em64t-6.0", "em64t-5.3", "em64t-5.2", "em64t-5.1", "em64t", 0 };
static const char* mkl_sfx_ia32[] = { "p4", "p3", "def", 0 };
static const char* mkl_sfx_ia64[] = { "i2p", "itp", 0 };
static const char* mkl_sfx_em64t[] = { "def", 0 };
const char** ipp_suffix = arch == CV_PROC_IA64 ? ipp_sfx_ia64 :
arch == CV_PROC_EM64T ? ipp_sfx_em64t : ipp_sfx_ia32;
const char** mkl_suffix = arch == CV_PROC_IA64 ? mkl_sfx_ia64 :
arch == CV_PROC_EM64T ? mkl_sfx_em64t : mkl_sfx_ia32;
for( i = 0; i < CV_PLUGIN_MAX; i++ )
plugins[i].basename = 0;
plugins[CV_PLUGIN_NONE].basename = 0;
plugins[CV_PLUGIN_NONE].name[0] = '\0';
plugins[CV_PLUGIN_OPTCV].basename = "ippopencv";
plugins[CV_PLUGIN_IPPCV].basename = "ippcv";
plugins[CV_PLUGIN_IPPI].basename = "ippi";
plugins[CV_PLUGIN_IPPS].basename = "ipps";
plugins[CV_PLUGIN_IPPVM].basename = "ippvm";
plugins[CV_PLUGIN_IPPCC].basename = "ippcc";
plugins[CV_PLUGIN_MKL].basename = "mkl_";
// try to load optimized dlls
for( i = 1; i < CV_PLUGIN_MAX; i++ )
{
// unload previously loaded optimized modules
if( plugins[i].handle )
{
FreeLibrary( plugins[i].handle );
plugins[i].handle = 0;
}
// do not load regular IPP modules if the custom merged IPP module is already found.
if( i < CV_PLUGIN_MKL && load_flag && plugins[CV_PLUGIN_OPTCV].handle != 0 )
continue;
if( load_flag && plugins[i].basename &&
(arch == CV_PROC_IA32_GENERIC || arch == CV_PROC_IA64 || arch == CV_PROC_EM64T) )
{
const char** suffix = i == CV_PLUGIN_OPTCV ? opencv_sfx :
i < CV_PLUGIN_MKL ? ipp_suffix : mkl_suffix;
if( suffix == mkl_sfx_ia32 )
{
if( !(cpu_info->model & CV_PROC_IA32_WITH_SSE2) )
suffix++;
if( !(cpu_info->model & CV_PROC_IA32_WITH_SSE) )
suffix++;
}
for( ; *suffix != 0; suffix++ )
{
sprintf( plugins[i].name, DLL_PREFIX "%s%s" DLL_DEBUG_FLAG DLL_SUFFIX,
plugins[i].basename, *suffix );
ICV_PRINTF(("loading %s...\n", plugins[i].name ));
plugins[i].handle = LoadLibrary( plugins[i].name );
if( plugins[i].handle != 0 )
{
ICV_PRINTF(("%s loaded\n", plugins[i].name ));
loaded_modules++;
break;
}
#ifndef WIN32
// temporary workaround for MacOSX
sprintf( plugins[i].name, DLL_PREFIX "%s%s" DLL_DEBUG_FLAG ".dylib",
plugins[i].basename, *suffix );
ICV_PRINTF(("loading %s...\n", plugins[i].name ));
plugins[i].handle = LoadLibrary( plugins[i].name );
if( plugins[i].handle != 0 )
{
ICV_PRINTF(("%s loaded\n", plugins[i].name ));
loaded_modules++;
break;
}
#endif
}
}
}
for( module = CvModule::first; module != 0; module = module->next )
loaded_functions += icvUpdatePluginFuncTab( module->func_tab );
return loaded_functions;
}
CvModule cxcore_module( &cxcore_info );
CV_IMPL void
cvGetModuleInfo( const char* name, const char **version, const char **plugin_list )
{
static char joint_verinfo[1024] = "";
static char plugin_list_buf[1024] = "";
CV_FUNCNAME( "cvGetLibraryInfo" );
if( version )
*version = 0;
if( plugin_list )
*plugin_list = 0;
__BEGIN__;
CvModuleInfo* module;
if( version )
{
if( name )
{
size_t i, name_len = strlen(name);
for( module = CvModule::first; module != 0; module = module->next )
{
if( strlen(module->name) == name_len )
{
for( i = 0; i < name_len; i++ )
{
int c0 = toupper(module->name[i]), c1 = toupper(name[i]);
if( c0 != c1 )
break;
}
if( i == name_len )
break;
}
}
if( !module )
CV_ERROR( CV_StsObjectNotFound, "The module is not found" );
*version = module->version;
}
else
{
char* ptr = joint_verinfo;
for( module = CvModule::first; module != 0; module = module->next )
{
sprintf( ptr, "%s: %s%s", module->name, module->version, module->next ? ", " : "" );
ptr += strlen(ptr);
}
*version = joint_verinfo;
}
}
if( plugin_list )
{
char* ptr = plugin_list_buf;
int i;
for( i = 0; i < CV_PLUGIN_MAX; i++ )
if( plugins[i].handle != 0 )
{
sprintf( ptr, "%s, ", plugins[i].name );
ptr += strlen(ptr);
}
if( ptr > plugin_list_buf )
{
ptr[-2] = '\0';
*plugin_list = plugin_list_buf;
}
else
*plugin_list = "";
}
__END__;
}
typedef int64 (CV_CDECL * rdtsc_func)(void);
/* helper functions for RNG initialization and accurate time measurement */
CV_IMPL int64 cvGetTickCount( void )
{
const CvProcessorInfo* cpu_info = icvGetProcessorInfo();
if( cpu_info->frequency > 1 &&
CV_GET_PROC_ARCH(cpu_info->model) == CV_PROC_IA32_GENERIC )
{
#ifdef MASM_INLINE_ASSEMBLY
#ifdef __BORLANDC__
__asm db 0fh
__asm db 31h
#else
__asm _emit 0x0f;
__asm _emit 0x31;
#endif
#elif (defined __GNUC__ || defined CV_ICC) && defined __i386__
int64 t;
asm volatile (".byte 0xf; .byte 0x31" /* "rdtsc" */ : "=A" (t));
return t;
#else
static const char code[] = "\x0f\x31\xc3";
rdtsc_func func = (rdtsc_func)(void*)code;
return func();
#endif
}
else
{
#if defined WIN32 || defined WIN64
LARGE_INTEGER counter;
QueryPerformanceCounter( &counter );
return (int64)counter.QuadPart;
#else
struct timeval tv;
struct timezone tz;
gettimeofday( &tv, &tz );
return (int64)tv.tv_sec*1000000 + tv.tv_usec;
#endif
}
}
CV_IMPL double cvGetTickFrequency()
{
return icvGetProcessorInfo()->frequency;
}
static int icvNumThreads = 0;
static int icvNumProcs = 0;
CV_IMPL int cvGetNumThreads(void)
{
if( !icvNumProcs )
cvSetNumThreads(0);
return icvNumThreads;
}
CV_IMPL void cvSetNumThreads( int threads )
{
if( !icvNumProcs )
{
#ifdef _OPENMP
icvNumProcs = omp_get_num_procs();
icvNumProcs = MIN( icvNumProcs, CV_MAX_THREADS );
#else
icvNumProcs = 1;
#endif
}
#ifdef _OPENMP
if( threads <= 0 )
threads = icvNumProcs;
//else
// threads = MIN( threads, icvNumProcs );
icvNumThreads = threads;
#else
icvNumThreads = 1;
#endif
}
CV_IMPL int cvGetThreadNum(void)
{
#ifdef _OPENMP
return omp_get_thread_num();
#else
return 0;
#endif
}
/* End of file. */