From 17ca7f95458fe1ae9c84e63d1c851e65949ce63d Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Thu, 12 Dec 2013 19:59:22 +0400 Subject: [PATCH] ocl: add support for initialization from user-provided OpenCL handles --- modules/ocl/CMakeLists.txt | 3 + .../ocl/doc/structures_and_utility_functions.rst | 16 +- modules/ocl/include/opencv2/ocl/ocl.hpp | 6 + modules/ocl/src/cl_context.cpp | 441 +++++++++++++-------- modules/ocl/test/test_api.cpp | 86 +++- 5 files changed, 380 insertions(+), 172 deletions(-) diff --git a/modules/ocl/CMakeLists.txt b/modules/ocl/CMakeLists.txt index 21e0b30..db9d64e 100644 --- a/modules/ocl/CMakeLists.txt +++ b/modules/ocl/CMakeLists.txt @@ -5,4 +5,7 @@ endif() set(the_description "OpenCL-accelerated Computer Vision") ocv_define_module(ocl opencv_core opencv_imgproc opencv_features2d opencv_objdetect opencv_video opencv_calib3d opencv_ml "${OPENCL_LIBRARIES}") +if(TARGET opencv_test_ocl) + target_link_libraries(opencv_test_ocl "${OPENCL_LIBRARIES}") +endif() ocv_warnings_disable(CMAKE_CXX_FLAGS -Wshadow) diff --git a/modules/ocl/doc/structures_and_utility_functions.rst b/modules/ocl/doc/structures_and_utility_functions.rst index aec3f70..1d1265c 100644 --- a/modules/ocl/doc/structures_and_utility_functions.rst +++ b/modules/ocl/doc/structures_and_utility_functions.rst @@ -25,12 +25,26 @@ Returns the list of devices ocl::setDevice -------------- -Returns void +Initialize OpenCL computation context .. ocv:function:: void ocl::setDevice( const DeviceInfo* info ) :param info: device info +ocl::initializeContext +-------------------------------- +Alternative way to initialize OpenCL computation context. + +.. ocv:function:: void ocl::initializeContext(void* pClPlatform, void* pClContext, void* pClDevice) + + :param pClPlatform: selected ``platform_id`` (via pointer, parameter type is ``cl_platform_id*``) + + :param pClContext: selected ``cl_context`` (via pointer, parameter type is ``cl_context*``) + + :param pClDevice: selected ``cl_device_id`` (via pointer, parameter type is ``cl_device_id*``) + +This function can be used for context initialization with D3D/OpenGL interoperability. + ocl::setBinaryPath ------------------ Returns void diff --git a/modules/ocl/include/opencv2/ocl/ocl.hpp b/modules/ocl/include/opencv2/ocl/ocl.hpp index eb310a2..af42136 100644 --- a/modules/ocl/include/opencv2/ocl/ocl.hpp +++ b/modules/ocl/include/opencv2/ocl/ocl.hpp @@ -118,6 +118,7 @@ namespace cv const PlatformInfo* platform; DeviceInfo(); + ~DeviceInfo(); }; struct PlatformInfo @@ -136,6 +137,7 @@ namespace cv std::vector devices; PlatformInfo(); + ~PlatformInfo(); }; //////////////////////////////// Initialization & Info //////////////////////// @@ -151,6 +153,10 @@ namespace cv // set device you want to use CV_EXPORTS void setDevice(const DeviceInfo* info); + // Initialize from OpenCL handles directly. + // Argument types is (pointers): cl_platform_id*, cl_context*, cl_device_id* + CV_EXPORTS void initializeContext(void* pClPlatform, void* pClContext, void* pClDevice); + //////////////////////////////// Error handling //////////////////////// CV_EXPORTS void error(const char *error_string, const char *file, const int line, const char *func); diff --git a/modules/ocl/src/cl_context.cpp b/modules/ocl/src/cl_context.cpp index 7ab39cb..37d6bb3 100644 --- a/modules/ocl/src/cl_context.cpp +++ b/modules/ocl/src/cl_context.cpp @@ -57,6 +57,8 @@ namespace cv { namespace ocl { +using namespace cl_utils; + #if defined(WIN32) static bool __termination = false; #endif @@ -75,36 +77,10 @@ cv::Mutex& getInitializationMutex() return __module.initializationMutex; } - -struct PlatformInfoImpl +static cv::Mutex& getCurrentContextMutex() { - cl_platform_id platform_id; - - std::vector deviceIDs; - - PlatformInfo info; - - PlatformInfoImpl() - : platform_id(NULL) - { - } -}; - -struct DeviceInfoImpl -{ - cl_platform_id platform_id; - cl_device_id device_id; - - DeviceInfo info; - - DeviceInfoImpl() - : platform_id(NULL), device_id(NULL) - { - } -}; - -static std::vector global_platforms; -static std::vector global_devices; + return __module.currentContextMutex; +} static bool parseOpenCLVersion(const std::string& versionStr, int& major, int& minor) { @@ -135,6 +111,141 @@ static bool parseOpenCLVersion(const std::string& versionStr, int& major, int& m return true; } +struct PlatformInfoImpl : public PlatformInfo +{ + cl_platform_id platform_id; + + std::vector deviceIDs; + + PlatformInfoImpl() + : platform_id(NULL) + { + } + + void init(int id, cl_platform_id platform) + { + CV_Assert(platform_id == NULL); + + this->_id = id; + platform_id = platform; + + openCLSafeCall(getStringInfo(clGetPlatformInfo, platform, CL_PLATFORM_PROFILE, this->platformProfile)); + openCLSafeCall(getStringInfo(clGetPlatformInfo, platform, CL_PLATFORM_VERSION, this->platformVersion)); + openCLSafeCall(getStringInfo(clGetPlatformInfo, platform, CL_PLATFORM_NAME, this->platformName)); + openCLSafeCall(getStringInfo(clGetPlatformInfo, platform, CL_PLATFORM_VENDOR, this->platformVendor)); + openCLSafeCall(getStringInfo(clGetPlatformInfo, platform, CL_PLATFORM_EXTENSIONS, this->platformExtensons)); + + parseOpenCLVersion(this->platformVersion, + this->platformVersionMajor, this->platformVersionMinor); + } + +}; + +struct DeviceInfoImpl: public DeviceInfo +{ + cl_platform_id platform_id; + cl_device_id device_id; + + DeviceInfoImpl() + : platform_id(NULL), device_id(NULL) + { + } + + void init(int id, PlatformInfoImpl& platformInfoImpl, cl_device_id device) + { + CV_Assert(device_id == NULL); + + this->_id = id; + platform_id = platformInfoImpl.platform_id; + device_id = device; + + this->platform = &platformInfoImpl; + + cl_device_type type = cl_device_type(-1); + openCLSafeCall(getScalarInfo(clGetDeviceInfo, device, CL_DEVICE_TYPE, type)); + this->deviceType = DeviceType(type); + + openCLSafeCall(getStringInfo(clGetDeviceInfo, device, CL_DEVICE_PROFILE, this->deviceProfile)); + openCLSafeCall(getStringInfo(clGetDeviceInfo, device, CL_DEVICE_VERSION, this->deviceVersion)); + openCLSafeCall(getStringInfo(clGetDeviceInfo, device, CL_DEVICE_NAME, this->deviceName)); + openCLSafeCall(getStringInfo(clGetDeviceInfo, device, CL_DEVICE_VENDOR, this->deviceVendor)); + cl_uint vendorID = 0; + openCLSafeCall(getScalarInfo(clGetDeviceInfo, device, CL_DEVICE_VENDOR_ID, vendorID)); + this->deviceVendorId = vendorID; + openCLSafeCall(getStringInfo(clGetDeviceInfo, device, CL_DRIVER_VERSION, this->deviceDriverVersion)); + openCLSafeCall(getStringInfo(clGetDeviceInfo, device, CL_DEVICE_EXTENSIONS, this->deviceExtensions)); + + parseOpenCLVersion(this->deviceVersion, + this->deviceVersionMajor, this->deviceVersionMinor); + + size_t maxWorkGroupSize = 0; + openCLSafeCall(getScalarInfo(clGetDeviceInfo, device, CL_DEVICE_MAX_WORK_GROUP_SIZE, maxWorkGroupSize)); + this->maxWorkGroupSize = maxWorkGroupSize; + + cl_uint maxDimensions = 0; + openCLSafeCall(getScalarInfo(clGetDeviceInfo, device, CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, maxDimensions)); + std::vector maxWorkItemSizes(maxDimensions); + openCLSafeCall(clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_ITEM_SIZES, sizeof(size_t) * maxDimensions, + (void *)&maxWorkItemSizes[0], 0)); + this->maxWorkItemSizes = maxWorkItemSizes; + + cl_uint maxComputeUnits = 0; + openCLSafeCall(getScalarInfo(clGetDeviceInfo, device, CL_DEVICE_MAX_COMPUTE_UNITS, maxComputeUnits)); + this->maxComputeUnits = maxComputeUnits; + + cl_ulong localMemorySize = 0; + openCLSafeCall(getScalarInfo(clGetDeviceInfo, device, CL_DEVICE_LOCAL_MEM_SIZE, localMemorySize)); + this->localMemorySize = (size_t)localMemorySize; + + cl_ulong maxMemAllocSize = 0; + openCLSafeCall(getScalarInfo(clGetDeviceInfo, device, CL_DEVICE_MAX_MEM_ALLOC_SIZE, maxMemAllocSize)); + this->maxMemAllocSize = (size_t)maxMemAllocSize; + + cl_bool unifiedMemory = false; + openCLSafeCall(getScalarInfo(clGetDeviceInfo, device, CL_DEVICE_HOST_UNIFIED_MEMORY, unifiedMemory)); + this->isUnifiedMemory = unifiedMemory != 0; + + //initialize extra options for compilation. Currently only fp64 is included. + //Assume 4KB is enough to store all possible extensions. + openCLSafeCall(getStringInfo(clGetDeviceInfo, device, CL_DEVICE_EXTENSIONS, this->deviceExtensions)); + + size_t fp64_khr = this->deviceExtensions.find("cl_khr_fp64"); + if(fp64_khr != std::string::npos) + { + this->compilationExtraOptions += "-D DOUBLE_SUPPORT"; + this->haveDoubleSupport = true; + } + else + { + this->haveDoubleSupport = false; + } + + size_t intel_platform = platformInfoImpl.platformVendor.find("Intel"); + if(intel_platform != std::string::npos) + { + this->compilationExtraOptions += " -D INTEL_DEVICE"; + this->isIntelDevice = true; + } + else + { + this->isIntelDevice = false; + } + + if (id < 0) + { +#ifdef CL_VERSION_1_2 + if (this->deviceVersionMajor > 1 || (this->deviceVersionMajor == 1 && this->deviceVersionMinor >= 2)) + { + ::clRetainDevice(device); + } +#endif + } + } +}; + +static std::vector global_platforms; +static std::vector global_devices; + static void split(const std::string &s, char delim, std::vector &elems) { std::stringstream ss(s); std::string item; @@ -333,8 +444,6 @@ not_found: static bool __initialized = false; static int initializeOpenCLDevices() { - using namespace cl_utils; - assert(!__initialized); __initialized = true; @@ -355,19 +464,9 @@ static int initializeOpenCLDevices() for (size_t i = 0; i < platforms.size(); ++i) { PlatformInfoImpl& platformInfo = global_platforms[i]; - platformInfo.info._id = i; cl_platform_id platform = platforms[i]; - - platformInfo.platform_id = platform; - openCLSafeCall(getStringInfo(clGetPlatformInfo, platform, CL_PLATFORM_PROFILE, platformInfo.info.platformProfile)); - openCLSafeCall(getStringInfo(clGetPlatformInfo, platform, CL_PLATFORM_VERSION, platformInfo.info.platformVersion)); - openCLSafeCall(getStringInfo(clGetPlatformInfo, platform, CL_PLATFORM_NAME, platformInfo.info.platformName)); - openCLSafeCall(getStringInfo(clGetPlatformInfo, platform, CL_PLATFORM_VENDOR, platformInfo.info.platformVendor)); - openCLSafeCall(getStringInfo(clGetPlatformInfo, platform, CL_PLATFORM_EXTENSIONS, platformInfo.info.platformExtensons)); - - parseOpenCLVersion(platformInfo.info.platformVersion, - platformInfo.info.platformVersionMajor, platformInfo.info.platformVersionMinor); + platformInfo.init(i, platform); std::vector devices; cl_int status = getDevices(platform, CL_DEVICE_TYPE_ALL, devices); @@ -379,89 +478,15 @@ static int initializeOpenCLDevices() int baseIndx = global_devices.size(); global_devices.resize(baseIndx + devices.size()); platformInfo.deviceIDs.resize(devices.size()); - platformInfo.info.devices.resize(devices.size()); + platformInfo.devices.resize(devices.size()); for(size_t j = 0; j < devices.size(); ++j) { cl_device_id device = devices[j]; DeviceInfoImpl& deviceInfo = global_devices[baseIndx + j]; - deviceInfo.info._id = baseIndx + j; - deviceInfo.platform_id = platform; - deviceInfo.device_id = device; - - deviceInfo.info.platform = &platformInfo.info; - platformInfo.deviceIDs[j] = deviceInfo.info._id; - - cl_device_type type = cl_device_type(-1); - openCLSafeCall(getScalarInfo(clGetDeviceInfo, device, CL_DEVICE_TYPE, type)); - deviceInfo.info.deviceType = DeviceType(type); - - openCLSafeCall(getStringInfo(clGetDeviceInfo, device, CL_DEVICE_PROFILE, deviceInfo.info.deviceProfile)); - openCLSafeCall(getStringInfo(clGetDeviceInfo, device, CL_DEVICE_VERSION, deviceInfo.info.deviceVersion)); - openCLSafeCall(getStringInfo(clGetDeviceInfo, device, CL_DEVICE_NAME, deviceInfo.info.deviceName)); - openCLSafeCall(getStringInfo(clGetDeviceInfo, device, CL_DEVICE_VENDOR, deviceInfo.info.deviceVendor)); - cl_uint vendorID = 0; - openCLSafeCall(getScalarInfo(clGetDeviceInfo, device, CL_DEVICE_VENDOR_ID, vendorID)); - deviceInfo.info.deviceVendorId = vendorID; - openCLSafeCall(getStringInfo(clGetDeviceInfo, device, CL_DRIVER_VERSION, deviceInfo.info.deviceDriverVersion)); - openCLSafeCall(getStringInfo(clGetDeviceInfo, device, CL_DEVICE_EXTENSIONS, deviceInfo.info.deviceExtensions)); - - parseOpenCLVersion(deviceInfo.info.deviceVersion, - deviceInfo.info.deviceVersionMajor, deviceInfo.info.deviceVersionMinor); - - size_t maxWorkGroupSize = 0; - openCLSafeCall(getScalarInfo(clGetDeviceInfo, device, CL_DEVICE_MAX_WORK_GROUP_SIZE, maxWorkGroupSize)); - deviceInfo.info.maxWorkGroupSize = maxWorkGroupSize; - - cl_uint maxDimensions = 0; - openCLSafeCall(getScalarInfo(clGetDeviceInfo, device, CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, maxDimensions)); - std::vector maxWorkItemSizes(maxDimensions); - openCLSafeCall(clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_ITEM_SIZES, sizeof(size_t) * maxDimensions, - (void *)&maxWorkItemSizes[0], 0)); - deviceInfo.info.maxWorkItemSizes = maxWorkItemSizes; - - cl_uint maxComputeUnits = 0; - openCLSafeCall(getScalarInfo(clGetDeviceInfo, device, CL_DEVICE_MAX_COMPUTE_UNITS, maxComputeUnits)); - deviceInfo.info.maxComputeUnits = maxComputeUnits; - - cl_ulong localMemorySize = 0; - openCLSafeCall(getScalarInfo(clGetDeviceInfo, device, CL_DEVICE_LOCAL_MEM_SIZE, localMemorySize)); - deviceInfo.info.localMemorySize = (size_t)localMemorySize; - - cl_ulong maxMemAllocSize = 0; - openCLSafeCall(getScalarInfo(clGetDeviceInfo, device, CL_DEVICE_MAX_MEM_ALLOC_SIZE, maxMemAllocSize)); - deviceInfo.info.maxMemAllocSize = (size_t)maxMemAllocSize; - - cl_bool unifiedMemory = false; - openCLSafeCall(getScalarInfo(clGetDeviceInfo, device, CL_DEVICE_HOST_UNIFIED_MEMORY, unifiedMemory)); - deviceInfo.info.isUnifiedMemory = unifiedMemory != 0; - - //initialize extra options for compilation. Currently only fp64 is included. - //Assume 4KB is enough to store all possible extensions. - openCLSafeCall(getStringInfo(clGetDeviceInfo, device, CL_DEVICE_EXTENSIONS, deviceInfo.info.deviceExtensions)); - - size_t fp64_khr = deviceInfo.info.deviceExtensions.find("cl_khr_fp64"); - if(fp64_khr != std::string::npos) - { - deviceInfo.info.compilationExtraOptions += "-D DOUBLE_SUPPORT"; - deviceInfo.info.haveDoubleSupport = true; - } - else - { - deviceInfo.info.haveDoubleSupport = false; - } - - size_t intel_platform = platformInfo.info.platformVendor.find("Intel"); - if(intel_platform != std::string::npos) - { - deviceInfo.info.compilationExtraOptions += " -D INTEL_DEVICE"; - deviceInfo.info.isIntelDevice = true; - } - else - { - deviceInfo.info.isIntelDevice = false; - } + platformInfo.deviceIDs[j] = baseIndx + j; + deviceInfo.init(baseIndx + j, platformInfo, device); } } } @@ -472,7 +497,7 @@ static int initializeOpenCLDevices() for(size_t j = 0; j < platformInfo.deviceIDs.size(); ++j) { DeviceInfoImpl& deviceInfo = global_devices[platformInfo.deviceIDs[j]]; - platformInfo.info.devices[j] = &deviceInfo.info; + platformInfo.devices[j] = &deviceInfo; } } @@ -491,6 +516,8 @@ DeviceInfo::DeviceInfo() // nothing } +DeviceInfo::~DeviceInfo() { } + PlatformInfo::PlatformInfo() : _id(-1), platformVersionMajor(0), platformVersionMinor(0) @@ -498,6 +525,8 @@ PlatformInfo::PlatformInfo() // nothing } +PlatformInfo::~PlatformInfo() { } + class ContextImpl; struct CommandQueue @@ -535,35 +564,97 @@ cv::TLSData commandQueueTLSData; class ContextImpl : public Context { public: - const cl_device_id clDeviceID; + cl_device_id clDeviceID; cl_context clContext; - const DeviceInfo& deviceInfo; + const DeviceInfoImpl& deviceInfoImpl; protected: - ContextImpl(const DeviceInfo& deviceInfo, cl_device_id clDeviceID) - : clDeviceID(clDeviceID), clContext(NULL), deviceInfo(deviceInfo) + ContextImpl(const DeviceInfoImpl& _deviceInfoImpl, cl_context context) + : clDeviceID(_deviceInfoImpl.device_id), clContext(context), deviceInfoImpl(_deviceInfoImpl) { - // nothing +#ifdef CL_VERSION_1_2 + if (supportsFeature(FEATURE_CL_VER_1_2)) + { + openCLSafeCall(clRetainDevice(clDeviceID)); + } +#endif + openCLSafeCall(clRetainContext(clContext)); + + ContextImpl* old = NULL; + { + cv::AutoLock lock(getCurrentContextMutex()); + old = currentContext; + currentContext = this; + } + if (old != NULL) + { + delete old; + } + } + ~ContextImpl() + { + CV_Assert(this != currentContext); + +#ifdef CL_VERSION_1_2 + if (supportsFeature(FEATURE_CL_VER_1_2)) + { + openCLSafeCall(clReleaseDevice(clDeviceID)); + } +#endif + if (deviceInfoImpl._id < 0) // not in the global registry, so we should cleanup it + { +#ifdef CL_VERSION_1_2 + if (supportsFeature(FEATURE_CL_VER_1_2)) + { + openCLSafeCall(clReleaseDevice(deviceInfoImpl.device_id)); + } +#endif + PlatformInfoImpl* platformImpl = (PlatformInfoImpl*)(deviceInfoImpl.platform); + delete platformImpl; + delete const_cast(&deviceInfoImpl); + } + clDeviceID = NULL; + +#ifdef WIN32 + // if process is on termination stage (ExitProcess was called and other threads were terminated) + // then disable command queue release because it may cause program hang + if (!__termination) +#endif + { + if(clContext) + { + openCLSafeCall(clReleaseContext(clContext)); + } + } + clContext = NULL; } - ~ContextImpl(); public: static void setContext(const DeviceInfo* deviceInfo); + static void initializeContext(void* pClPlatform, void* pClContext, void* pClDevice); bool supportsFeature(FEATURE_TYPE featureType) const; static void cleanupContext(void); + static ContextImpl* getContext(); private: ContextImpl(const ContextImpl&); // disabled ContextImpl& operator=(const ContextImpl&); // disabled + + static ContextImpl* currentContext; }; -static ContextImpl* currentContext = NULL; +ContextImpl* ContextImpl::currentContext = NULL; static bool __deviceSelected = false; Context* Context::getContext() { + return ContextImpl::getContext(); +} + +ContextImpl* ContextImpl::getContext() +{ if (currentContext == NULL) { static bool defaultInitiaization = false; @@ -606,7 +697,7 @@ bool Context::supportsFeature(FEATURE_TYPE featureType) const const DeviceInfo& Context::getDeviceInfo() const { - return ((ContextImpl*)this)->deviceInfo; + return ((ContextImpl*)this)->deviceInfoImpl; } const void* Context::getOpenCLContextPtr() const @@ -636,34 +727,18 @@ bool ContextImpl::supportsFeature(FEATURE_TYPE featureType) const switch (featureType) { case FEATURE_CL_INTEL_DEVICE: - return deviceInfo.isIntelDevice; + return deviceInfoImpl.isIntelDevice; case FEATURE_CL_DOUBLE: - return deviceInfo.haveDoubleSupport; + return deviceInfoImpl.haveDoubleSupport; case FEATURE_CL_UNIFIED_MEM: - return deviceInfo.isUnifiedMemory; + return deviceInfoImpl.isUnifiedMemory; case FEATURE_CL_VER_1_2: - return deviceInfo.deviceVersionMajor > 1 || (deviceInfo.deviceVersionMajor == 1 && deviceInfo.deviceVersionMinor >= 2); + return deviceInfoImpl.deviceVersionMajor > 1 || (deviceInfoImpl.deviceVersionMajor == 1 && deviceInfoImpl.deviceVersionMinor >= 2); } CV_Error(CV_StsBadArg, "Invalid feature type"); return false; } -ContextImpl::~ContextImpl() -{ -#ifdef WIN32 - // if process is on termination stage (ExitProcess was called and other threads were terminated) - // then disable command queue release because it may cause program hang - if (!__termination) -#endif - { - if(clContext) - { - openCLSafeCall(clReleaseContext(clContext)); - } - } - clContext = NULL; -} - void fft_teardown(); void clBlasTeardown(); @@ -672,46 +747,58 @@ void ContextImpl::cleanupContext(void) fft_teardown(); clBlasTeardown(); - cv::AutoLock lock(__module.currentContextMutex); + cv::AutoLock lock(getCurrentContextMutex()); if (currentContext) - delete currentContext; - currentContext = NULL; + { + ContextImpl* ctx = currentContext; + currentContext = NULL; + delete ctx; + } } void ContextImpl::setContext(const DeviceInfo* deviceInfo) { - CV_Assert(deviceInfo->_id >= 0 && deviceInfo->_id < (int)global_devices.size()); + CV_Assert(deviceInfo->_id >= 0); // we can't specify custom devices + CV_Assert(deviceInfo->_id < (int)global_devices.size()); { - cv::AutoLock lock(__module.currentContextMutex); + cv::AutoLock lock(getCurrentContextMutex()); if (currentContext) { - if (currentContext->deviceInfo._id == deviceInfo->_id) + if (currentContext->deviceInfoImpl._id == deviceInfo->_id) return; } } DeviceInfoImpl& infoImpl = global_devices[deviceInfo->_id]; - CV_Assert(deviceInfo == &infoImpl.info); + CV_Assert(deviceInfo == &infoImpl); cl_int status = 0; cl_context_properties cps[3] = { CL_CONTEXT_PLATFORM, (cl_context_properties)(infoImpl.platform_id), 0 }; cl_context clContext = clCreateContext(cps, 1, &infoImpl.device_id, NULL, NULL, &status); openCLVerifyCall(status); - ContextImpl* ctx = new ContextImpl(infoImpl.info, infoImpl.device_id); - ctx->clContext = clContext; + ContextImpl* ctx = new ContextImpl(infoImpl, clContext); + clReleaseContext(clContext); + (void)ctx; +} - ContextImpl* old = NULL; - { - cv::AutoLock lock(__module.currentContextMutex); - old = currentContext; - currentContext = ctx; - } - if (old != NULL) - { - delete old; - } +void ContextImpl::initializeContext(void* pClPlatform, void* pClContext, void* pClDevice) +{ + CV_Assert(pClPlatform != NULL); + CV_Assert(pClContext != NULL); + CV_Assert(pClDevice != NULL); + cl_platform_id platform = *(cl_platform_id*)pClPlatform; + cl_context context = *(cl_context*)pClContext; + cl_device_id device = *(cl_device_id*)pClDevice; + + PlatformInfoImpl* platformInfoImpl = new PlatformInfoImpl(); + platformInfoImpl->init(-1, platform); + DeviceInfoImpl* deviceInfoImpl = new DeviceInfoImpl(); + deviceInfoImpl->init(-1, *platformInfoImpl, device); + + ContextImpl* ctx = new ContextImpl(*deviceInfoImpl, context); + (void)ctx; } void CommandQueue::create(ContextImpl* context) @@ -735,7 +822,7 @@ int getOpenCLPlatforms(PlatformsInfo& platforms) for (size_t id = 0; id < global_platforms.size(); ++id) { PlatformInfoImpl& impl = global_platforms[id]; - platforms.push_back(&impl.info); + platforms.push_back(&impl); } return platforms.size(); @@ -765,9 +852,9 @@ int getOpenCLDevices(std::vector &devices, int deviceType, co for (size_t id = 0; id < global_devices.size(); ++id) { DeviceInfoImpl& deviceInfo = global_devices[id]; - if (((int)deviceInfo.info.deviceType & deviceType) != 0) + if (((int)deviceInfo.deviceType & deviceType) != 0) { - devices.push_back(&deviceInfo.info); + devices.push_back(&deviceInfo); } } } @@ -800,6 +887,20 @@ void setDevice(const DeviceInfo* info) } } +void initializeContext(void* pClPlatform, void* pClContext, void* pClDevice) +{ + try + { + ContextImpl::initializeContext(pClPlatform, pClContext, pClDevice); + __deviceSelected = true; + } + catch (...) + { + __deviceSelected = true; + throw; + } +} + bool supportsFeature(FEATURE_TYPE featureType) { return Context::getContext()->supportsFeature(featureType); diff --git a/modules/ocl/test/test_api.cpp b/modules/ocl/test/test_api.cpp index 36eb8bd..44dd794 100644 --- a/modules/ocl/test/test_api.cpp +++ b/modules/ocl/test/test_api.cpp @@ -40,7 +40,7 @@ //M*/ #include "test_precomp.hpp" -#include "opencv2/ocl/cl_runtime/cl_runtime.hpp" // for OpenCL types: cl_mem +#include "opencv2/ocl/cl_runtime/cl_runtime.hpp" // for OpenCL types & functions TEST(TestAPI, openCLExecuteKernelInterop) { @@ -78,3 +78,87 @@ TEST(TestAPI, openCLExecuteKernelInterop) EXPECT_LE(checkNorm(cpuMat, dst), 1e-3); } + +// This test must be DISABLED by default! +// (We can't restore original context for other tests) +TEST(TestAPI, DISABLED_InitializationFromHandles) +{ +#define MAX_PLATFORMS 16 + cl_platform_id platforms[MAX_PLATFORMS] = { NULL }; + cl_uint numPlatforms = 0; + cl_int status = ::clGetPlatformIDs(MAX_PLATFORMS, &platforms[0], &numPlatforms); + ASSERT_EQ(CL_SUCCESS, status) << "clGetPlatformIDs"; + ASSERT_NE(0, (int)numPlatforms); + + int selectedPlatform = 0; + cl_platform_id platform = platforms[selectedPlatform]; + + ASSERT_NE((void*)NULL, platform); + + cl_device_id device = NULL; + status = ::clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, 1, &device, NULL); + ASSERT_EQ(CL_SUCCESS, status) << "clGetDeviceIDs"; + ASSERT_NE((void*)NULL, device); + + cl_context_properties cps[3] = { CL_CONTEXT_PLATFORM, (cl_context_properties)(platform), 0 }; + cl_context context = ::clCreateContext(cps, 1, &device, NULL, NULL, &status); + ASSERT_EQ(CL_SUCCESS, status) << "clCreateContext"; + ASSERT_NE((void*)NULL, context); + + ASSERT_NO_THROW(cv::ocl::initializeContext(&platform, &context, &device)); + + status = ::clReleaseContext(context); + ASSERT_EQ(CL_SUCCESS, status) << "clReleaseContext"; + +#ifdef CL_VERSION_1_2 +#if 1 + { + cv::ocl::Context* ctx = cv::ocl::Context::getContext(); + ASSERT_NE((void*)NULL, ctx); + if (ctx->supportsFeature(cv::ocl::FEATURE_CL_VER_1_2)) // device supports OpenCL 1.2+ + { + status = ::clReleaseDevice(device); + ASSERT_EQ(CL_SUCCESS, status) << "clReleaseDevice"; + } + } +#else // code below doesn't work on Linux (SEGFAULTs on 1.1- devices are not handled via exceptions) + try + { + status = ::clReleaseDevice(device); // NOTE This works only with !DEVICES! that supports OpenCL 1.2 + (void)status; // no check + } + catch (...) + { + // nothing, there is no problem + } +#endif +#endif + + // print the name of current device + cv::ocl::Context* ctx = cv::ocl::Context::getContext(); + ASSERT_NE((void*)NULL, ctx); + const cv::ocl::DeviceInfo& deviceInfo = ctx->getDeviceInfo(); + std::cout << "Device name: " << deviceInfo.deviceName << std::endl; + std::cout << "Platform name: " << deviceInfo.platform->platformName << std::endl; + + ASSERT_EQ(context, *(cl_context*)ctx->getOpenCLContextPtr()); + ASSERT_EQ(device, *(cl_device_id*)ctx->getOpenCLDeviceIDPtr()); + + // do some calculations and check results + cv::RNG rng; + Size sz(100, 100); + cv::Mat srcMat = cvtest::randomMat(rng, sz, CV_32FC4, -10, 10, false); + cv::Mat dstMat; + + cv::ocl::oclMat srcGpuMat(srcMat); + cv::ocl::oclMat dstGpuMat; + + cv::Scalar v = cv::Scalar::all(1); + cv::add(srcMat, v, dstMat); + cv::ocl::add(srcGpuMat, v, dstGpuMat); + + cv::Mat dstGpuMatMap; + dstGpuMat.download(dstGpuMatMap); + + EXPECT_LE(checkNorm(dstMat, dstGpuMatMap), 1e-3); +} -- 2.7.4