From 212ad971003e69645c7ee64d9e120fdee6d8ccbf Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Sun, 15 Sep 2013 02:45:02 +0400 Subject: [PATCH] ocl: dynamic load of OpenCL libraries Support functions from OpenCL 1.1 / OpenCL 1.2 --- CMakeLists.txt | 9 +- cmake/OpenCVDetectOpenCL.cmake | 67 +++--- cmake/checks/opencl11.cpp | 14 ++ cmake/checks/opencl12.cpp | 14 ++ cmake/templates/cvconfig.h.cmake | 2 + .../opencv2/ocl/cl_runtime/cl_runtime.hpp | 19 ++ .../ocl/include/opencv2/ocl/private/util.hpp | 6 +- modules/ocl/src/cl_runtime/cl_runtime.cpp | 105 +++++++++ .../ocl/src/cl_runtime/generator/common.py | 199 ++++++++++++++++++ .../ocl/src/cl_runtime/generator/generate.sh | 7 + .../ocl/src/cl_runtime/generator/parser_cl.py | 112 ++++++++++ .../cl_runtime/generator/parser_clamdblas.py | 107 ++++++++++ .../cl_runtime/generator/parser_clamdfft.py | 104 +++++++++ .../template/cl_runtime_impl_opencl.hpp.in | 10 + .../template/cl_runtime_opencl.hpp.in | 34 +++ .../template/clamdblas_runtime.cpp.in | 75 +++++++ .../template/clamdblas_runtime.hpp.in | 25 +++ .../template/clamdfft_runtime.cpp.in | 75 +++++++ .../template/clamdfft_runtime.hpp.in | 25 +++ modules/ocl/src/fft.cpp | 2 +- modules/ocl/src/gemm.cpp | 2 +- modules/ocl/src/precomp.hpp | 10 + modules/ocl/src/safe_call.hpp | 6 +- 23 files changed, 975 insertions(+), 54 deletions(-) create mode 100644 cmake/checks/opencl11.cpp create mode 100644 cmake/checks/opencl12.cpp create mode 100644 modules/ocl/include/opencv2/ocl/cl_runtime/cl_runtime.hpp create mode 100644 modules/ocl/src/cl_runtime/cl_runtime.cpp create mode 100644 modules/ocl/src/cl_runtime/generator/common.py create mode 100644 modules/ocl/src/cl_runtime/generator/generate.sh create mode 100644 modules/ocl/src/cl_runtime/generator/parser_cl.py create mode 100644 modules/ocl/src/cl_runtime/generator/parser_clamdblas.py create mode 100644 modules/ocl/src/cl_runtime/generator/parser_clamdfft.py create mode 100644 modules/ocl/src/cl_runtime/generator/template/cl_runtime_impl_opencl.hpp.in create mode 100644 modules/ocl/src/cl_runtime/generator/template/cl_runtime_opencl.hpp.in create mode 100644 modules/ocl/src/cl_runtime/generator/template/clamdblas_runtime.cpp.in create mode 100644 modules/ocl/src/cl_runtime/generator/template/clamdblas_runtime.hpp.in create mode 100644 modules/ocl/src/cl_runtime/generator/template/clamdfft_runtime.cpp.in create mode 100644 modules/ocl/src/cl_runtime/generator/template/clamdfft_runtime.hpp.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a1598d132..532fd88207 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -824,7 +824,14 @@ endif() if(HAVE_OPENCL) status("") - status(" OpenCL") + status(" OpenCL:") + set(__opencl_ver "invalid") + if(HAVE_OPENCL12) + set(__opencl_ver "1.2") + elseif(HAVE_OPENCL11) + set(__opencl_ver "1.1") + endif() + status(" Version:" ${__opencl_ver}) if(OPENCL_INCLUDE_DIR) status(" Include path:" ${OPENCL_INCLUDE_DIRS}) endif() diff --git a/cmake/OpenCVDetectOpenCL.cmake b/cmake/OpenCVDetectOpenCL.cmake index 2c96274a8c..7ed54b565d 100644 --- a/cmake/OpenCVDetectOpenCL.cmake +++ b/cmake/OpenCVDetectOpenCL.cmake @@ -6,7 +6,7 @@ if(APPLE) else(APPLE) #find_package(OpenCL QUIET) - if (NOT OPENCL_FOUND) + if(NOT OPENCL_FOUND) find_path(OPENCL_ROOT_DIR NAMES OpenCL/cl.h CL/cl.h include/CL/cl.h include/nvidia-current/CL/cl.h PATHS ENV OCLROOT ENV AMDAPPSDKROOT ENV CUDA_PATH ENV INTELOCLSDKROOT @@ -20,18 +20,7 @@ else(APPLE) DOC "OpenCL include directory" NO_DEFAULT_PATH) - if (X86_64) - set(OPENCL_POSSIBLE_LIB_SUFFIXES lib/Win64 lib/x86_64 lib/x64) - elseif (X86) - set(OPENCL_POSSIBLE_LIB_SUFFIXES lib/Win32 lib/x86) - endif() - - find_library(OPENCL_LIBRARY - NAMES OpenCL - HINTS ${OPENCL_ROOT_DIR} - PATH_SUFFIXES ${OPENCL_POSSIBLE_LIB_SUFFIXES} - DOC "OpenCL library" - NO_DEFAULT_PATH) + set(OPENCL_LIBRARY "OPENCL_DYNAMIC_LOAD") mark_as_advanced(OPENCL_INCLUDE_DIR OPENCL_LIBRARY) include(FindPackageHandleStandardArgs) @@ -40,20 +29,30 @@ else(APPLE) endif(APPLE) if(OPENCL_FOUND) - set(HAVE_OPENCL 1) - set(OPENCL_INCLUDE_DIRS ${OPENCL_INCLUDE_DIR}) - set(OPENCL_LIBRARIES ${OPENCL_LIBRARY}) - - if(WIN32 AND X86_64) - set(CLAMD_POSSIBLE_LIB_SUFFIXES lib64/import) - elseif(WIN32) - set(CLAMD_POSSIBLE_LIB_SUFFIXES lib32/import) + try_compile(HAVE_OPENCL11 + "${OpenCV_BINARY_DIR}" + "${OpenCV_SOURCE_DIR}/cmake/checks/opencl11.cpp" + CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:STRING=${OPENCL_INCLUDE_DIR}" + ) + if(NOT HAVE_OPENCL11) + message(STATUS "OpenCL 1.1 not found, ignore OpenCL SDK") + return() + endif() + try_compile(HAVE_OPENCL12 + "${OpenCV_BINARY_DIR}" + "${OpenCV_SOURCE_DIR}/cmake/checks/opencl12.cpp" + CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:STRING=${OPENCL_INCLUDE_DIR}" + ) + if(NOT HAVE_OPENCL12) + message(STATUS "OpenCL 1.2 not found, will use OpenCL 1.1") endif() - if(X86_64 AND UNIX) - set(CLAMD_POSSIBLE_LIB_SUFFIXES lib64) - elseif(X86 AND UNIX) - set(CLAMD_POSSIBLE_LIB_SUFFIXES lib32) + set(HAVE_OPENCL 1) + set(OPENCL_INCLUDE_DIRS ${OPENCL_INCLUDE_DIR}) + if(OPENCL_LIBRARY MATCHES "OPENCL_DYNAMIC_LOAD") + unset(OPENCL_LIBRARIES) + else() + set(OPENCL_LIBRARIES "${OPENCL_LIBRARY}") endif() if(WITH_OPENCLAMDFFT) @@ -70,16 +69,9 @@ if(OPENCL_FOUND) PATH_SUFFIXES include DOC "clAmdFft include directory") - find_library(CLAMDFFT_LIBRARY - NAMES clAmdFft.Runtime - HINTS ${CLAMDFFT_ROOT_DIR} - PATH_SUFFIXES ${CLAMD_POSSIBLE_LIB_SUFFIXES} - DOC "clAmdFft library") - - if(CLAMDFFT_LIBRARY AND CLAMDFFT_INCLUDE_DIR) + if(CLAMDFFT_INCLUDE_DIR) set(HAVE_CLAMDFFT 1) list(APPEND OPENCL_INCLUDE_DIRS "${CLAMDFFT_INCLUDE_DIR}") - list(APPEND OPENCL_LIBRARIES "${CLAMDFFT_LIBRARY}") endif() endif() @@ -97,16 +89,9 @@ if(OPENCL_FOUND) PATH_SUFFIXES include DOC "clAmdFft include directory") - find_library(CLAMDBLAS_LIBRARY - NAMES clAmdBlas - HINTS ${CLAMDBLAS_ROOT_DIR} - PATH_SUFFIXES ${CLAMD_POSSIBLE_LIB_SUFFIXES} - DOC "clAmdBlas library") - - if(CLAMDBLAS_LIBRARY AND CLAMDBLAS_INCLUDE_DIR) + if(CLAMDBLAS_INCLUDE_DIR) set(HAVE_CLAMDBLAS 1) list(APPEND OPENCL_INCLUDE_DIRS "${CLAMDBLAS_INCLUDE_DIR}") - list(APPEND OPENCL_LIBRARIES "${CLAMDBLAS_LIBRARY}") endif() endif() endif() diff --git a/cmake/checks/opencl11.cpp b/cmake/checks/opencl11.cpp new file mode 100644 index 0000000000..b17889d1d4 --- /dev/null +++ b/cmake/checks/opencl11.cpp @@ -0,0 +1,14 @@ +#if defined __APPLE__ +#include +#else +#include +#endif + +int main(int argc, char** argv) +{ +#ifdef CL_VERSION_1_1 +#else +#error OpenCL 1.1 not found +#endif + return 0; +} diff --git a/cmake/checks/opencl12.cpp b/cmake/checks/opencl12.cpp new file mode 100644 index 0000000000..639502e02a --- /dev/null +++ b/cmake/checks/opencl12.cpp @@ -0,0 +1,14 @@ +#if defined __APPLE__ +#include +#else +#include +#endif + +int main(int argc, char** argv) +{ +#ifdef CL_VERSION_1_2 +#else +#error OpenCL 1.2 not found +#endif + return 0; +} diff --git a/cmake/templates/cvconfig.h.cmake b/cmake/templates/cvconfig.h.cmake index 960becf381..14eb519d01 100644 --- a/cmake/templates/cvconfig.h.cmake +++ b/cmake/templates/cvconfig.h.cmake @@ -108,6 +108,8 @@ /* OpenCL Support */ #cmakedefine HAVE_OPENCL +#cmakedefine HAVE_OPENCL11 +#cmakedefine HAVE_OPENCL12 /* OpenEXR codec */ #cmakedefine HAVE_OPENEXR diff --git a/modules/ocl/include/opencv2/ocl/cl_runtime/cl_runtime.hpp b/modules/ocl/include/opencv2/ocl/cl_runtime/cl_runtime.hpp new file mode 100644 index 0000000000..7b31f457e7 --- /dev/null +++ b/modules/ocl/include/opencv2/ocl/cl_runtime/cl_runtime.hpp @@ -0,0 +1,19 @@ +// +// AUTOGENERATED, DO NOT EDIT +// +#ifndef __OPENCV_OCL_CL_RUNTIME_HPP__ +#define __OPENCV_OCL_CL_RUNTIME_HPP__ + +#ifdef HAVE_OPENCL + +#if defined(HAVE_OPENCL12) +#include "cl_runtime_opencl12.hpp" +#elif defined(HAVE_OPENCL11) +#include "cl_runtime_opencl11.hpp" +#else +#error Invalid OpenCL configuration +#endif + +#endif + +#endif // __OPENCV_OCL_CL_RUNTIME_HPP__ diff --git a/modules/ocl/include/opencv2/ocl/private/util.hpp b/modules/ocl/include/opencv2/ocl/private/util.hpp index 9adae38230..3de0d438d4 100644 --- a/modules/ocl/include/opencv2/ocl/private/util.hpp +++ b/modules/ocl/include/opencv2/ocl/private/util.hpp @@ -48,11 +48,7 @@ #include "opencv2/ocl/ocl.hpp" -#if defined __APPLE__ -#include -#else -#include -#endif +#include "opencv2/ocl/cl_runtime/cl_runtime.hpp" namespace cv { diff --git a/modules/ocl/src/cl_runtime/cl_runtime.cpp b/modules/ocl/src/cl_runtime/cl_runtime.cpp new file mode 100644 index 0000000000..c237afe74c --- /dev/null +++ b/modules/ocl/src/cl_runtime/cl_runtime.cpp @@ -0,0 +1,105 @@ +#include "precomp.hpp" + +#if defined(HAVE_OPENCL) && (!defined(__APPLE__) || defined(IOS)) + +#if defined(BUILD_SHARED_LIBS) && (defined WIN32 || defined _WIN32 || defined WINCE) +#define CL_RUNTIME_EXPORT __declspec(dllexport) +#else +#define CL_RUNTIME_EXPORT +#endif + + +#include "opencv2/ocl/cl_runtime/cl_runtime.hpp" + +#if defined(__APPLE__) + #include + + static void* AppleCLGetProcAddress(const char* name) + { + static void * image = NULL; + if (!image) + { + image = dlopen("/System/Library/Frameworks/OpenCL.framework/Versions/Current/OpenCL", RTLD_LAZY | RTLD_GLOBAL); + if (!image) + return NULL; + } + + return dlsym(image, name); + } + #define CV_CL_GET_PROC_ADDRESS(name) AppleCLGetProcAddress(name) +#endif // __APPLE__ + +#if defined(_WIN32) + static void* WinGetProcAddress(const char* name) + { + static HMODULE opencl_module = NULL; + if (!opencl_module) + { + opencl_module = GetModuleHandleA("OpenCL.dll"); + if (!opencl_module) + { + const char* name = "OpenCL.dll"; + const char* envOpenCLBinary = getenv("OPENCV_OPENCL_BINARY"); + if (envOpenCLBinary) + name = envOpenCLBinary; + opencl_module = LoadLibraryA(name); + if (!opencl_module) + return NULL; + } + } + return (void*)GetProcAddress(opencl_module, name); + } + #define CV_CL_GET_PROC_ADDRESS(name) WinGetProcAddress(name) +#endif // _WIN32 + +#if defined(linux) + #include + #include + + static void* GetProcAddress (const char* name) + { + static void* h = NULL; + if (!h) + { + const char* name = "libOpenCL.so"; + const char* envOpenCLBinary = getenv("OPENCV_OPENCL_BINARY"); + if (envOpenCLBinary) + name = envOpenCLBinary; + h = dlopen(name, RTLD_LAZY | RTLD_GLOBAL); + if (!h) + return NULL; + } + + return dlsym(h, name); + } + #define CV_CL_GET_PROC_ADDRESS(name) GetProcAddress(name) +#endif + +#ifndef CV_CL_GET_PROC_ADDRESS +#define CV_CL_GET_PROC_ADDRESS(name) NULL +#endif + +static void* opencl_check_fn(int ID) +{ + extern const char* opencl_fn_names[]; + void* func = CV_CL_GET_PROC_ADDRESS(opencl_fn_names[ID]); + if (!func) + { + std::ostringstream msg; + msg << "OpenCL function is not available: [" << opencl_fn_names[ID] << "]"; + CV_Error(CV_StsBadFunc, msg.str()); + } + extern void* opencl_fn_ptrs[]; + *(void**)(opencl_fn_ptrs[ID]) = func; + return func; +} + +#if defined(HAVE_OPENCL12) +#include "cl_runtime_opencl12_impl.hpp" +#elif defined(HAVE_OPENCL11) +#include "cl_runtime_opencl11_impl.hpp" +#else +#error Invalid OpenCL configuration +#endif + +#endif diff --git a/modules/ocl/src/cl_runtime/generator/common.py b/modules/ocl/src/cl_runtime/generator/common.py new file mode 100644 index 0000000000..99a56096b0 --- /dev/null +++ b/modules/ocl/src/cl_runtime/generator/common.py @@ -0,0 +1,199 @@ +import sys, os, re + +# +# Parser helpers +# + +def remove_comments(s): + def replacer(match): + s = match.group(0) + if s.startswith('/'): + return "" + else: + return s + pattern = re.compile( + r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"', + re.DOTALL | re.MULTILINE + ) + return re.sub(pattern, replacer, s) + + +def getTokens(s): + return re.findall(r'[a-z_A-Z0-9_]+|[^[a-z_A-Z0-9_ \n\r\t]', s) + + +def getParameter(pos, tokens): + deep = 0 + p = [] + while True: + if pos >= len(tokens): + break + if (tokens[pos] == ')' or tokens[pos] == ',') and deep == 0: + if tokens[pos] == ')': + pos = len(tokens) + else: + pos += 1 + break + if tokens[pos] == '(': + deep += 1 + if tokens[pos] == ')': + deep -= 1 + p.append(tokens[pos]) + pos += 1 + return (' '.join(p), pos) + + +def getParameters(i, tokens): + assert tokens[i] == '(' + i += 1 + + params = [] + while True: + if i >= len(tokens) or tokens[i] == ')': + break + + (param, i) = getParameter(i, tokens) + if len(param) > 0: + params.append(param) + else: + assert False + break + + if len(params) > 0 and params[0] == 'void': + del params[0] + + return params + +def postProcessParameters(fns): + for fn in fns: + fn['params_full'] = list(fn['params']) + for i in range(len(fn['params'])): + p = fn['params'][i] + if p.find('(') != -1: + p = re.sub(r'\* *([a-zA-Z0-9_]*) ?\)', '*)', p, 1) + fn['params'][i] = p + continue + parts = re.findall(r'[a-z_A-Z0-9]+|\*', p) + if len(parts) > 1: + if parts[-1].find('*') == -1: + del parts[-1] + fn['params'][i] = ' '.join(parts) + +# +# Generator helpers +# + +def outputToString(f): + def wrapped(*args, **kwargs): + from cStringIO import StringIO + old_stdout = sys.stdout + sys.stdout = str_stdout = StringIO() + res = f(*args, **kwargs) + assert res is None + sys.stdout = old_stdout + result = str_stdout.getvalue() + result = re.sub(r'([^\n ]) [ ]+', r'\1 ', result) # don't remove spaces at start of line + result = re.sub(r' ,', ',', result) + result = re.sub(r' \*', '*', result) + result = re.sub(r'\( ', '(', result) + result = re.sub(r' \)', ')', result) + return result + return wrapped + +@outputToString +def generateEnums(fns, prefix='OPENCL_FN'): + print '// generated by %s' % os.path.basename(sys.argv[0]) + print 'enum %s_ID {' % prefix + first = True + for fn in fns: + print ' %s_%s%s,' % (prefix, fn['name'], ' = 0' if first else '') + first = False + print '};' + +@outputToString +def generateNames(fns, prefix='opencl_fn'): + print '// generated by %s' % os.path.basename(sys.argv[0]) + print 'const char* %s_names[] = {' % prefix + for fn in fns: + print ' "%s",' % (fn['name']) + print '};' + +@outputToString +def generatePtrs(fns, prefix='opencl_fn'): + print '// generated by %s' % os.path.basename(sys.argv[0]) + print 'void* %s_ptrs[] = {' % prefix + for fn in fns: + print ' &%s,' % (fn['name']) + print '};' + +@outputToString +def generateRemapOrigin(fns): + print '// generated by %s' % os.path.basename(sys.argv[0]) + for fn in fns: + print '#define %s %s_' % (fn['name'], fn['name']) + +@outputToString +def generateRemapDynamic(fns): + print '// generated by %s' % os.path.basename(sys.argv[0]) + for fn in fns: + print '#undef %s' % (fn['name']) + print '#define %s %s_pfn' % (fn['name'], fn['name']) + +@outputToString +def generateParamsCfg(fns): + for fn in fns: + print '%s %d' % (fn['name'], len(fn['params'])) + +@outputToString +def generateFnDeclaration(fns): + print '// generated by %s' % os.path.basename(sys.argv[0]) + for fn in fns: + print 'extern CL_RUNTIME_EXPORT %s %s (%s *%s)(%s);' % (' '.join(fn['modifiers']), ' '.join(fn['ret']), ' '.join(fn['calling']), + fn['name'], ', '.join(fn['params'] if not fn.has_key('params_full') else fn['params_full'])) + +@outputToString +def generateFnDefinition(fns, lprefix='opencl_fn', uprefix='OPENCL_FN'): + print '// generated by %s' % os.path.basename(sys.argv[0]) + for fn in fns: + print '%s%s (%s *%s)(%s) = %s%d<%s_%s, %s%s>::switch_fn;' % \ + ((' '.join(fn['modifiers'] + ' ') if len(fn['modifiers']) > 0 else ''), + ' '.join(fn['ret']), ' '.join(fn['calling']), fn['name'], ', '.join(fn['params']), \ + lprefix, len(fn['params']), uprefix, fn['name'], ' '.join(fn['ret']), ('' if len(fn['params']) == 0 else ', ' + ', '.join(fn['params']))) + +@outputToString +def generateTemplates(sz, lprefix, switch_name, calling_convention=''): + print '// generated by %s' % os.path.basename(sys.argv[0]) + for sz in range(sz): + template_params = ['int ID', 'typename _R'] + types = [] + types_with_params = [] + params = [] + for i in range(1, sz + 1): + template_params.append('typename _T%d' % i) + types.append('_T%d' % i) + types_with_params.append('_T%d p%d' % (i, i)) + params.append('p%d' % i) + print 'template <%s>' % ', '.join(template_params) + print 'struct %s%d' % (lprefix, sz) + print '{' + print ' typedef _R (%s *FN)(%s);' % (calling_convention, ', '.join(types)) + print ' static _R %s switch_fn(%s)' % (calling_convention, ', '.join(types_with_params)) + print ' { return ((FN)%s(ID))(%s); }' % (switch_name, ', '.join(params)) + print '};' + print '' + + +def ProcessTemplate(inputFile, ctx, noteLine='//\n// AUTOGENERATED, DO NOT EDIT\n//'): + f = open(inputFile, "r") + if noteLine: + print noteLine + for line in f: + if line.startswith('@'): + assert line[-1] == '\n' + line = line[:-1] # remove '\n' + assert line[-1] == '@' + name = line[1:-1] + assert ctx.has_key(name), name + line = ctx[name] + print line, + f.close() diff --git a/modules/ocl/src/cl_runtime/generator/generate.sh b/modules/ocl/src/cl_runtime/generator/generate.sh new file mode 100644 index 0000000000..5be039dfef --- /dev/null +++ b/modules/ocl/src/cl_runtime/generator/generate.sh @@ -0,0 +1,7 @@ +#!/bin/bash -e +echo "Generate files for CL runtime..." +cat sources/opencl11/cl.h | python parser_cl.py cl_runtime_opencl11 +cat sources/opencl12/cl.h | python parser_cl.py cl_runtime_opencl12 +cat sources/clAmdBlas.h | python parser_clamdblas.py +cat sources/clAmdFft.h | python parser_clamdfft.py +echo "Generate files for CL runtime... Done" diff --git a/modules/ocl/src/cl_runtime/generator/parser_cl.py b/modules/ocl/src/cl_runtime/generator/parser_cl.py new file mode 100644 index 0000000000..e711e4cf09 --- /dev/null +++ b/modules/ocl/src/cl_runtime/generator/parser_cl.py @@ -0,0 +1,112 @@ +#!/bin/python +# usage: +# cat opencl11/cl.h | $0 cl_runtime_opencl11 +# cat opencl12/cl.h | $0 cl_runtime_opencl12 +import sys, re; + +from common import remove_comments, getTokens, getParameters, postProcessParameters + +try: + if len(sys.argv) > 1: + outfile = open('../../../include/opencv2/ocl/cl_runtime/' + sys.argv[1] + '.hpp', "w") + outfile_impl = open('../' + sys.argv[1] + '_impl.hpp', "w") + if len(sys.argv) > 2: + f = open(sys.argv[2], "r") + else: + f = sys.stdin + else: + sys.exit("ERROR. Specify output file") +except: + sys.exit("ERROR. Can't open input/output file, check parameters") + +fns = [] + +while True: + line = f.readline() + if len(line) == 0: + break + assert isinstance(line, str) + parts = line.split(); + if line.startswith('extern') and line.find('CL_API_CALL') != -1: + # read block of lines + while True: + nl = f.readline() + nl = nl.strip() + nl = re.sub(r'\n', r'', nl) + if len(nl) == 0: + break; + line += ' ' + nl + + line = remove_comments(line) + + parts = getTokens(line) + + fn = {} + modifiers = [] + ret = [] + calling = [] + i = 1 + while (i < len(parts)): + if parts[i].startswith('CL_'): + modifiers.append(parts[i]) + else: + break + i += 1 + while (i < len(parts)): + if not parts[i].startswith('CL_'): + ret.append(parts[i]) + else: + break + i += 1 + while (i < len(parts)): + calling.append(parts[i]) + i += 1 + if parts[i - 1] == 'CL_API_CALL': + break + + fn['modifiers'] = [] # modifiers + fn['ret'] = ret + fn['calling'] = [] # calling + + # print 'modifiers='+' '.join(modifiers) + # print 'ret='+' '.join(type) + # print 'calling='+' '.join(calling) + + name = parts[i]; i += 1; + fn['name'] = name + print 'name=' + name + + params = getParameters(i, parts) + + fn['params'] = params + # print 'params="'+','.join(params)+'"' + + fns.append(fn) + +f.close() + +print 'Found %d functions' % len(fns) + +postProcessParameters(fns) + +from pprint import pprint +pprint(fns) + +from common import * + +ctx = {} +ctx['CL_REMAP_ORIGIN'] = generateRemapOrigin(fns) +ctx['CL_REMAP_DYNAMIC'] = generateRemapDynamic(fns) +ctx['CL_FN_DECLARATIONS'] = generateFnDeclaration(fns) + +sys.stdout = outfile +ProcessTemplate('template/cl_runtime_opencl.hpp.in', ctx) + +ctx['CL_FN_ENUMS'] = generateEnums(fns) +ctx['CL_FN_NAMES'] = generateNames(fns) +ctx['CL_FN_DEFINITIONS'] = generateFnDefinition(fns) +ctx['CL_FN_PTRS'] = generatePtrs(fns) +ctx['CL_FN_SWITCH'] = generateTemplates(15, 'opencl_fn', 'opencl_check_fn') + +sys.stdout = outfile_impl +ProcessTemplate('template/cl_runtime_impl_opencl.hpp.in', ctx) diff --git a/modules/ocl/src/cl_runtime/generator/parser_clamdblas.py b/modules/ocl/src/cl_runtime/generator/parser_clamdblas.py new file mode 100644 index 0000000000..52e62c5de8 --- /dev/null +++ b/modules/ocl/src/cl_runtime/generator/parser_clamdblas.py @@ -0,0 +1,107 @@ +#!/bin/python +# usage: +# cat clAmdBlas.h | $0 +import sys, re; + +from common import remove_comments, getTokens, getParameters, postProcessParameters + +try: + if len(sys.argv) > 1: + f = open(sys.argv[1], "r") + else: + f = sys.stdin +except: + sys.exit("ERROR. Can't open input file") + +fns = [] + +while True: + line = f.readline() + if len(line) == 0: + break + assert isinstance(line, str) + line = line.strip() + parts = line.split(); + if (line.startswith('clAmd') or line.startswith('cl_') or line == 'void') and len(line.split()) == 1 and line.find('(') == -1: + fn = {} + modifiers = [] + ret = [] + calling = [] + i = 0 + while (i < len(parts)): + if parts[i].startswith('CL_'): + modifiers.append(parts[i]) + else: + break + i += 1 + while (i < len(parts)): + if not parts[i].startswith('CL_'): + ret.append(parts[i]) + else: + break + i += 1 + while (i < len(parts)): + calling.append(parts[i]) + i += 1 + fn['modifiers'] = [] # modifiers + fn['ret'] = ret + fn['calling'] = calling + + # print 'modifiers='+' '.join(modifiers) + # print 'ret='+' '.join(type) + # print 'calling='+' '.join(calling) + + # read block of lines + line = f.readline() + while True: + nl = f.readline() + nl = nl.strip() + nl = re.sub(r'\n', r'', nl) + if len(nl) == 0: + break; + line += ' ' + nl + + line = remove_comments(line) + + parts = getTokens(line) + + i = 0; + + name = parts[i]; i += 1; + fn['name'] = name + print 'name=' + name + + params = getParameters(i, parts) + + fn['params'] = params + # print 'params="'+','.join(params)+'"' + + fns.append(fn) + +f.close() + +print 'Found %d functions' % len(fns) + +postProcessParameters(fns) + +from pprint import pprint +pprint(fns) + +from common import * + +ctx = {} +ctx['CLAMDBLAS_REMAP_ORIGIN'] = generateRemapOrigin(fns) +ctx['CLAMDBLAS_REMAP_DYNAMIC'] = generateRemapDynamic(fns) +ctx['CLAMDBLAS_FN_DECLARATIONS'] = generateFnDeclaration(fns) + +sys.stdout = open('../../../include/opencv2/ocl/cl_runtime/clamdblas_runtime.hpp', 'w') +ProcessTemplate('template/clamdblas_runtime.hpp.in', ctx) + +ctx['CL_FN_ENUMS'] = generateEnums(fns, 'OPENCLAMDBLAS_FN') +ctx['CL_FN_NAMES'] = generateNames(fns, 'openclamdblas_fn') +ctx['CL_FN_DEFINITIONS'] = generateFnDefinition(fns, 'openclamdblas_fn', 'OPENCLAMDBLAS_FN') +ctx['CL_FN_PTRS'] = generatePtrs(fns, 'openclamdblas_fn') +ctx['CL_FN_SWITCH'] = generateTemplates(23, 'openclamdblas_fn', 'openclamdblas_check_fn', '') + +sys.stdout = open('../clamdblas_runtime.cpp', 'w') +ProcessTemplate('template/clamdblas_runtime.cpp.in', ctx) diff --git a/modules/ocl/src/cl_runtime/generator/parser_clamdfft.py b/modules/ocl/src/cl_runtime/generator/parser_clamdfft.py new file mode 100644 index 0000000000..35b78cad43 --- /dev/null +++ b/modules/ocl/src/cl_runtime/generator/parser_clamdfft.py @@ -0,0 +1,104 @@ +#!/bin/python +# usage: +# cat clAmdFft.h | $0 +import sys, re; + +from common import remove_comments, getTokens, getParameters, postProcessParameters + + +try: + if len(sys.argv) > 1: + f = open(sys.argv[1], "r") + else: + f = sys.stdin +except: + sys.exit("ERROR. Can't open input file") + +fns = [] + +while True: + line = f.readline() + if len(line) == 0: + break + assert isinstance(line, str) + line = line.strip() + if line.startswith('CLAMDFFTAPI'): + line = re.sub(r'\n', r'', line) + while True: + nl = f.readline() + nl = nl.strip() + nl = re.sub(r'\n', r'', nl) + if len(nl) == 0: + break; + line += ' ' + nl + + line = remove_comments(line) + + parts = getTokens(line) + + fn = {} + modifiers = [] + ret = [] + calling = [] + + i = 0 + while True: + if parts[i] == "CLAMDFFTAPI": + modifiers.append(parts[i]) + else: + break + i += 1 + while (i < len(parts)): + if not parts[i] == '(': + ret.append(parts[i]) + else: + del ret[-1] + i -= 1 + break + i += 1 + + fn['modifiers'] = [] # modifiers + fn['ret'] = ret + fn['calling'] = calling + + name = parts[i]; i += 1; + fn['name'] = name + print 'name=' + name + + params = getParameters(i, parts) + + if len(params) > 0 and params[0] == 'void': + del params[0] + + fn['params'] = params + # print 'params="'+','.join(params)+'"' + + fns.append(fn) + +f.close() + +print 'Found %d functions' % len(fns) + +postProcessParameters(fns) + +from pprint import pprint +pprint(fns) + +from common import * + +ctx = {} +ctx['CLAMDFFT_REMAP_ORIGIN'] = generateRemapOrigin(fns) +ctx['CLAMDFFT_REMAP_DYNAMIC'] = generateRemapDynamic(fns) +ctx['CLAMDFFT_FN_DECLARATIONS'] = generateFnDeclaration(fns) + +sys.stdout = open('../../../include/opencv2/ocl/cl_runtime/clamdfft_runtime.hpp', 'w') +ProcessTemplate('template/clamdfft_runtime.hpp.in', ctx) + +ctx['CL_FN_ENUMS'] = generateEnums(fns, 'OPENCLAMDFFT_FN') +ctx['CL_FN_NAMES'] = generateNames(fns, 'openclamdfft_fn') +ctx['CL_FN_DEFINITIONS'] = generateFnDefinition(fns, 'openclamdfft_fn', 'OPENCLAMDFFT_FN') +ctx['CL_FN_PTRS'] = generatePtrs(fns, 'openclamdfft_fn') +ctx['CL_FN_SWITCH'] = generateTemplates(23, 'openclamdfft_fn', 'openclamdfft_check_fn', '') + +sys.stdout = open('../clamdfft_runtime.cpp', 'w') +ProcessTemplate('template/clamdfft_runtime.cpp.in', ctx) diff --git a/modules/ocl/src/cl_runtime/generator/template/cl_runtime_impl_opencl.hpp.in b/modules/ocl/src/cl_runtime/generator/template/cl_runtime_impl_opencl.hpp.in new file mode 100644 index 0000000000..ff0395dcd3 --- /dev/null +++ b/modules/ocl/src/cl_runtime/generator/template/cl_runtime_impl_opencl.hpp.in @@ -0,0 +1,10 @@ +@CL_FN_ENUMS@ +@CL_FN_NAMES@ + +namespace { +@CL_FN_SWITCH@ +} + +@CL_FN_DEFINITIONS@ + +@CL_FN_PTRS@ diff --git a/modules/ocl/src/cl_runtime/generator/template/cl_runtime_opencl.hpp.in b/modules/ocl/src/cl_runtime/generator/template/cl_runtime_opencl.hpp.in new file mode 100644 index 0000000000..0079cb696d --- /dev/null +++ b/modules/ocl/src/cl_runtime/generator/template/cl_runtime_opencl.hpp.in @@ -0,0 +1,34 @@ +#ifndef __OPENCV_OCL_CL_RUNTIME_OPENCL_HPP__ +#define __OPENCV_OCL_CL_RUNTIME_OPENCL_HPP__ + +#ifdef HAVE_OPENCL + +#if defined __APPLE__ && !defined(IOS) +#include +#else + +@CL_REMAP_ORIGIN@ + +#if defined __APPLE__ +#include +#else +#include +#endif + +@CL_REMAP_DYNAMIC@ + +#ifndef CL_RUNTIME_EXPORT +#if (defined(BUILD_SHARED_LIBS) || defined(OPENCV_OCL_SHARED)) && (defined WIN32 || defined _WIN32 || defined WINCE) +#define CL_RUNTIME_EXPORT __declspec(dllimport) +#else +#define CL_RUNTIME_EXPORT +#endif +#endif + +@CL_FN_DECLARATIONS@ + +#endif + +#endif + +#endif // __OPENCV_OCL_CL_RUNTIME_OPENCL_HPP__ diff --git a/modules/ocl/src/cl_runtime/generator/template/clamdblas_runtime.cpp.in b/modules/ocl/src/cl_runtime/generator/template/clamdblas_runtime.cpp.in new file mode 100644 index 0000000000..8492edda9e --- /dev/null +++ b/modules/ocl/src/cl_runtime/generator/template/clamdblas_runtime.cpp.in @@ -0,0 +1,75 @@ +#include "precomp.hpp" + +#ifdef HAVE_CLAMDBLAS + +#include "opencv2/ocl/cl_runtime/cl_runtime.hpp" +#include "opencv2/ocl/cl_runtime/clamdblas_runtime.hpp" + +#if defined(_WIN32) + static void* WinGetProcAddress(const char* name) + { + static HMODULE opencl_module = NULL; + if (!opencl_module) + { + opencl_module = GetModuleHandleA("clAmdBlas.dll"); + if (!opencl_module) + { + opencl_module = LoadLibraryA("clAmdBlas.dll"); + if (!opencl_module) + return NULL; + } + } + return (void*)GetProcAddress(opencl_module, name); + } + #define CV_CL_GET_PROC_ADDRESS(name) WinGetProcAddress(name) +#endif // _WIN32 + +#if defined(linux) + #include + #include + + static void* GetProcAddress (const char* name) + { + static void* h = NULL; + if (!h) + { + h = dlopen("libclAmdBlas.so", RTLD_LAZY | RTLD_GLOBAL); + if (!h) + return NULL; + } + + return dlsym(h, name); + } + #define CV_CL_GET_PROC_ADDRESS(name) GetProcAddress(name) +#endif + +#ifndef CV_CL_GET_PROC_ADDRESS +#define CV_CL_GET_PROC_ADDRESS(name) NULL +#endif + +@CL_FN_ENUMS@ +@CL_FN_NAMES@ + +static void* openclamdblas_check_fn(int ID) +{ + void* func = CV_CL_GET_PROC_ADDRESS(openclamdblas_fn_names[ID]); + if (!func) + { + std::ostringstream msg; + msg << "OpenCL AMD BLAS function is not available: [" << openclamdblas_fn_names[ID] << "]"; + CV_Error(CV_StsBadFunc, msg.str()); + } + extern void* openclamdblas_fn_ptrs[]; + *(void**)(openclamdblas_fn_ptrs[ID]) = func; + return func; +} + +namespace { +@CL_FN_SWITCH@ +} + +@CL_FN_DEFINITIONS@ + +@CL_FN_PTRS@ + +#endif diff --git a/modules/ocl/src/cl_runtime/generator/template/clamdblas_runtime.hpp.in b/modules/ocl/src/cl_runtime/generator/template/clamdblas_runtime.hpp.in new file mode 100644 index 0000000000..cbffb0861a --- /dev/null +++ b/modules/ocl/src/cl_runtime/generator/template/clamdblas_runtime.hpp.in @@ -0,0 +1,25 @@ +#ifndef __OPENCV_OCL_CLAMDBLAS_RUNTIME_HPP__ +#define __OPENCV_OCL_CLAMDBLAS_RUNTIME_HPP__ + +#ifdef HAVE_CLAMDBLAS + +@CLAMDBLAS_REMAP_ORIGIN@ + +#include + +@CLAMDBLAS_REMAP_DYNAMIC@ + +#ifndef CL_RUNTIME_EXPORT +#if (defined(BUILD_SHARED_LIBS) || defined(OPENCV_OCL_SHARED)) && (defined WIN32 || defined _WIN32 || defined WINCE) +#define CL_RUNTIME_EXPORT __declspec(dllimport) +#else +#define CL_RUNTIME_EXPORT +#endif +#endif + + +@CLAMDBLAS_FN_DECLARATIONS@ + +#endif + +#endif // __OPENCV_OCL_CLAMDBLAS_RUNTIME_HPP__ diff --git a/modules/ocl/src/cl_runtime/generator/template/clamdfft_runtime.cpp.in b/modules/ocl/src/cl_runtime/generator/template/clamdfft_runtime.cpp.in new file mode 100644 index 0000000000..aee6bd8ab6 --- /dev/null +++ b/modules/ocl/src/cl_runtime/generator/template/clamdfft_runtime.cpp.in @@ -0,0 +1,75 @@ +#include "precomp.hpp" + +#ifdef HAVE_CLAMDFFT + +#include "opencv2/ocl/cl_runtime/cl_runtime.hpp" +#include "opencv2/ocl/cl_runtime/clamdfft_runtime.hpp" + +#if defined(_WIN32) + static void* WinGetProcAddress(const char* name) + { + static HMODULE opencl_module = NULL; + if (!opencl_module) + { + opencl_module = GetModuleHandleA("clAmdFft.Runtime.dll"); + if (!opencl_module) + { + opencl_module = LoadLibraryA("clAmdFft.Runtime.dll"); + if (!opencl_module) + return NULL; + } + } + return (void*)GetProcAddress(opencl_module, name); + } + #define CV_CL_GET_PROC_ADDRESS(name) WinGetProcAddress(name) +#endif // _WIN32 + +#if defined(linux) + #include + #include + + static void* GetProcAddress (const char* name) + { + static void* h = NULL; + if (!h) + { + h = dlopen("libclAmdFft.Runtime.so", RTLD_LAZY | RTLD_GLOBAL); + if (!h) + return NULL; + } + + return dlsym(h, name); + } + #define CV_CL_GET_PROC_ADDRESS(name) GetProcAddress(name) +#endif + +#ifndef CV_CL_GET_PROC_ADDRESS +#define CV_CL_GET_PROC_ADDRESS(name) NULL +#endif + +@CL_FN_ENUMS@ +@CL_FN_NAMES@ + +static void* openclamdfft_check_fn(int ID) +{ + void* func = CV_CL_GET_PROC_ADDRESS(openclamdfft_fn_names[ID]); + if (!func) + { + std::ostringstream msg; + msg << "OpenCL AMD FFT function is not available: [" << openclamdfft_fn_names[ID] << "]"; + CV_Error(CV_StsBadFunc, msg.str()); + } + extern void* openclamdfft_fn_ptrs[]; + *(void**)(openclamdfft_fn_ptrs[ID]) = func; + return func; +} + +namespace { +@CL_FN_SWITCH@ +} + +@CL_FN_DEFINITIONS@ + +@CL_FN_PTRS@ + +#endif diff --git a/modules/ocl/src/cl_runtime/generator/template/clamdfft_runtime.hpp.in b/modules/ocl/src/cl_runtime/generator/template/clamdfft_runtime.hpp.in new file mode 100644 index 0000000000..5e26d0154e --- /dev/null +++ b/modules/ocl/src/cl_runtime/generator/template/clamdfft_runtime.hpp.in @@ -0,0 +1,25 @@ +#ifndef __OPENCV_OCL_CLAMDFFT_RUNTIME_HPP__ +#define __OPENCV_OCL_CLAMDFFT_RUNTIME_HPP__ + +#ifdef HAVE_CLAMDFFT + +@CLAMDFFT_REMAP_ORIGIN@ + +#include + +@CLAMDFFT_REMAP_DYNAMIC@ + +#ifndef CL_RUNTIME_EXPORT +#if (defined(BUILD_SHARED_LIBS) || defined(OPENCV_OCL_SHARED)) && (defined WIN32 || defined _WIN32 || defined WINCE) +#define CL_RUNTIME_EXPORT __declspec(dllimport) +#else +#define CL_RUNTIME_EXPORT +#endif +#endif + + +@CLAMDFFT_FN_DECLARATIONS@ + +#endif + +#endif // __OPENCV_OCL_CLAMDFFT_RUNTIME_HPP__ diff --git a/modules/ocl/src/fft.cpp b/modules/ocl/src/fft.cpp index 7aa40e8b7b..b6cc070fb5 100644 --- a/modules/ocl/src/fft.cpp +++ b/modules/ocl/src/fft.cpp @@ -59,7 +59,7 @@ namespace cv { namespace ocl { }} void cv::ocl::fft_teardown(){} #else -#include "clAmdFft.h" +#include "opencv2/ocl/cl_runtime/clamdfft_runtime.hpp" namespace cv { namespace ocl diff --git a/modules/ocl/src/gemm.cpp b/modules/ocl/src/gemm.cpp index 7e31cdbf4f..ec03c2f932 100644 --- a/modules/ocl/src/gemm.cpp +++ b/modules/ocl/src/gemm.cpp @@ -73,7 +73,7 @@ void cv::ocl::clBlasTeardown() } #else -#include "clAmdBlas.h" +#include "opencv2/ocl/cl_runtime/clamdblas_runtime.hpp" using namespace cv; static bool clBlasInitialized = false; diff --git a/modules/ocl/src/precomp.hpp b/modules/ocl/src/precomp.hpp index a50ab900ab..039e7ff061 100644 --- a/modules/ocl/src/precomp.hpp +++ b/modules/ocl/src/precomp.hpp @@ -52,8 +52,18 @@ #pragma warning( disable: 4267 4324 4244 4251 4710 4711 4514 4996 ) #endif +#if defined(_WIN32) +#include +#endif + #include "cvconfig.h" +#if defined(BUILD_SHARED_LIBS) && (defined WIN32 || defined _WIN32 || defined WINCE) +#define CL_RUNTIME_EXPORT __declspec(dllexport) +#else +#define CL_RUNTIME_EXPORT +#endif + #include #include #include diff --git a/modules/ocl/src/safe_call.hpp b/modules/ocl/src/safe_call.hpp index ba36cabd32..574400eefd 100644 --- a/modules/ocl/src/safe_call.hpp +++ b/modules/ocl/src/safe_call.hpp @@ -46,11 +46,7 @@ #ifndef __OPENCV_OPENCL_SAFE_CALL_HPP__ #define __OPENCV_OPENCL_SAFE_CALL_HPP__ -#if defined __APPLE__ -#include -#else -#include -#endif +#include "opencv2/ocl/cl_runtime/cl_runtime.hpp" #if defined(__GNUC__) #define openCLSafeCall(expr) ___openCLSafeCall(expr, __FILE__, __LINE__, __func__)