catching OpenCL double not supported exceptions
[profile/ivi/opencv.git] / modules / ocl / src / cl_context.cpp
1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                           License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2010-2012, Institute Of Software Chinese Academy Of Science, all rights reserved.
14 // Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved.
15 // Copyright (C) 2010-2012, Multicoreware, Inc., all rights reserved.
16 // Third party copyrights are property of their respective owners.
17 //
18 // @Authors
19 //    Guoping Long, longguoping@gmail.com
20 //    Niko Li, newlife20080214@gmail.com
21 //    Yao Wang, bitwangyaoyao@gmail.com
22 // Redistribution and use in source and binary forms, with or without modification,
23 // are permitted provided that the following conditions are met:
24 //
25 //   * Redistribution's of source code must retain the above copyright notice,
26 //     this list of conditions and the following disclaimer.
27 //
28 //   * Redistribution's in binary form must reproduce the above copyright notice,
29 //     this list of conditions and the following disclaimer in the documentation
30 //     and/or other oclMaterials provided with the distribution.
31 //
32 //   * The name of the copyright holders may not be used to endorse or promote products
33 //     derived from this software without specific prior written permission.
34 //
35 // This software is provided by the copyright holders and contributors "as is" and
36 // any express or implied warranties, including, but not limited to, the implied
37 // warranties of merchantability and fitness for a particular purpose are disclaimed.
38 // In no event shall the Intel Corporation or contributors be liable for any direct,
39 // indirect, incidental, special, exemplary, or consequential damages
40 // (including, but not limited to, procurement of substitute goods or services;
41 // loss of use, data, or profits; or business interruption) however caused
42 // and on any theory of liability, whether in contract, strict liability,
43 // or tort (including negligence or otherwise) arising in any way out of
44 // the use of this software, even if advised of the possibility of such damage.
45 //
46 //M*/
47
48 #include "precomp.hpp"
49 #include <iomanip>
50 #include <fstream>
51 #include "cl_programcache.hpp"
52
53 // workaround for OpenCL C++ bindings
54 #if defined(HAVE_OPENCL12)
55 #include "opencv2/ocl/cl_runtime/cl_runtime_opencl12_wrappers.hpp"
56 #elif defined(HAVE_OPENCL11)
57 #include "opencv2/ocl/cl_runtime/cl_runtime_opencl11_wrappers.hpp"
58 #else
59 #error Invalid OpenCL configuration
60 #endif
61
62 #if defined _MSC_VER && _MSC_VER >= 1200
63 #pragma warning( disable: 4100 4101 4127 4244 4267 4510 4512 4610)
64 #endif
65 #undef __CL_ENABLE_EXCEPTIONS
66 #include <CL/cl.hpp>
67
68 namespace cv {
69 namespace ocl {
70
71 struct PlatformInfoImpl
72 {
73     cl_platform_id platform_id;
74
75     std::vector<int> deviceIDs;
76
77     PlatformInfo info;
78
79     PlatformInfoImpl()
80         : platform_id(NULL)
81     {
82     }
83 };
84
85 struct DeviceInfoImpl
86 {
87     cl_platform_id platform_id;
88     cl_device_id device_id;
89
90     DeviceInfo info;
91
92     DeviceInfoImpl()
93         : platform_id(NULL), device_id(NULL)
94     {
95     }
96 };
97
98 static std::vector<PlatformInfoImpl> global_platforms;
99 static std::vector<DeviceInfoImpl> global_devices;
100
101 static bool parseOpenCLVersion(const std::string& versionStr, int& major, int& minor)
102 {
103     size_t p0 = versionStr.find(' ');
104     while (true)
105     {
106         if (p0 == std::string::npos)
107             break;
108         if (p0 + 1 >= versionStr.length())
109             break;
110         char c = versionStr[p0 + 1];
111         if (isdigit(c))
112             break;
113         p0 = versionStr.find(' ', p0 + 1);
114     }
115     size_t p1 = versionStr.find('.', p0);
116     size_t p2 = versionStr.find(' ', p1);
117     if (p0 == std::string::npos || p1 == std::string::npos || p2 == std::string::npos)
118     {
119         major = 0;
120         minor = 0;
121         return false;
122     }
123     std::string majorStr = versionStr.substr(p0 + 1, p1 - p0 - 1);
124     std::string minorStr = versionStr.substr(p1 + 1, p2 - p1 - 1);
125     major = atoi(majorStr.c_str());
126     minor = atoi(minorStr.c_str());
127     return true;
128 }
129
130 static void split(const std::string &s, char delim, std::vector<std::string> &elems) {
131     std::stringstream ss(s);
132     std::string item;
133     while (std::getline(ss, item, delim)) {
134         elems.push_back(item);
135     }
136 }
137
138 static std::vector<std::string> split(const std::string &s, char delim) {
139     std::vector<std::string> elems;
140     split(s, delim, elems);
141     return elems;
142 }
143
144 // Layout: <Platform>:<CPU|GPU|ACCELERATOR|nothing=GPU/CPU>:<deviceName>
145 // Sample: AMD:GPU:
146 // Sample: AMD:GPU:Tahiti
147 // Sample: :GPU|CPU: = '' = ':' = '::'
148 static bool parseOpenCLDeviceConfiguration(const std::string& configurationStr,
149         std::string& platform, std::vector<std::string>& deviceTypes, std::string& deviceNameOrID)
150 {
151     std::string deviceTypesStr;
152     size_t p0 = configurationStr.find(':');
153     if (p0 != std::string::npos)
154     {
155         size_t p1 = configurationStr.find(':', p0 + 1);
156         if (p1 != std::string::npos)
157         {
158             size_t p2 = configurationStr.find(':', p1 + 1);
159             if (p2 != std::string::npos)
160             {
161                 std::cerr << "ERROR: Invalid configuration string for OpenCL device" << std::endl;
162                 return false;
163             }
164             else
165             {
166                 // assume platform + device types + device name/id
167                 platform = configurationStr.substr(0, p0);
168                 deviceTypesStr = configurationStr.substr(p0 + 1, p1 - (p0 + 1));
169                 deviceNameOrID = configurationStr.substr(p1 + 1, configurationStr.length() - (p1 + 1));
170             }
171         }
172         else
173         {
174             // assume platform + device types
175             platform = configurationStr.substr(0, p0);
176             deviceTypesStr = configurationStr.substr(p0 + 1, configurationStr.length() - (p0 + 1));
177         }
178     }
179     else
180     {
181         // assume only platform
182         platform = configurationStr;
183     }
184     deviceTypes = split(deviceTypesStr, '|');
185     return true;
186 }
187
188 static bool __deviceSelected = false;
189 static bool selectOpenCLDevice()
190 {
191     __deviceSelected = true;
192
193     std::string platform;
194     std::vector<std::string> deviceTypes;
195     std::string deviceName;
196     const char* configuration = getenv("OPENCV_OPENCL_DEVICE");
197     if (configuration)
198     {
199         if (!parseOpenCLDeviceConfiguration(std::string(configuration), platform, deviceTypes, deviceName))
200             return false;
201     }
202
203     bool isID = false;
204     int deviceID = -1;
205     if (deviceName.length() == 1)
206     // We limit ID range to 0..9, because we want to write:
207     // - '2500' to mean i5-2500
208     // - '8350' to mean AMD FX-8350
209     // - '650' to mean GeForce 650
210     // To extend ID range change condition to '> 0'
211     {
212         isID = true;
213         for (size_t i = 0; i < deviceName.length(); i++)
214         {
215             if (!isdigit(deviceName[i]))
216             {
217                 isID = false;
218                 break;
219             }
220         }
221         if (isID)
222         {
223             deviceID = atoi(deviceName.c_str());
224             CV_Assert(deviceID >= 0);
225         }
226     }
227
228     const PlatformInfo* platformInfo = NULL;
229     if (platform.length() > 0)
230     {
231         PlatformsInfo platforms;
232         getOpenCLPlatforms(platforms);
233         for (size_t i = 0; i < platforms.size(); i++)
234         {
235             if (platforms[i]->platformName.find(platform) != std::string::npos)
236             {
237                 platformInfo = platforms[i];
238                 break;
239             }
240         }
241         if (platformInfo == NULL)
242         {
243             std::cerr << "ERROR: Can't find OpenCL platform by name: " << platform << std::endl;
244             goto not_found;
245         }
246     }
247
248     if (deviceTypes.size() == 0)
249     {
250         if (!isID)
251         {
252             deviceTypes.push_back("GPU");
253             deviceTypes.push_back("CPU");
254         }
255         else
256         {
257             deviceTypes.push_back("ALL");
258         }
259     }
260     for (size_t t = 0; t < deviceTypes.size(); t++)
261     {
262         int deviceType = 0;
263         if (deviceTypes[t] == "GPU")
264         {
265             deviceType = CVCL_DEVICE_TYPE_GPU;
266         }
267         else if (deviceTypes[t] == "CPU")
268         {
269             deviceType = CVCL_DEVICE_TYPE_CPU;
270         }
271         else if (deviceTypes[t] == "ACCELERATOR")
272         {
273             deviceType = CVCL_DEVICE_TYPE_ACCELERATOR;
274         }
275         else if (deviceTypes[t] == "ALL")
276         {
277             deviceType = CVCL_DEVICE_TYPE_ALL;
278         }
279         else
280         {
281             std::cerr << "ERROR: Unsupported device type for OpenCL device (GPU, CPU, ACCELERATOR): " << deviceTypes[t] << std::endl;
282             goto not_found;
283         }
284
285         DevicesInfo devices;
286         getOpenCLDevices(devices, deviceType, platformInfo);
287
288         for (size_t i = (isID ? deviceID : 0);
289              (isID ? (i == (size_t)deviceID) : true) && (i < devices.size());
290              i++)
291         {
292             if (isID || devices[i]->deviceName.find(deviceName) != std::string::npos)
293             {
294                 // check for OpenCL 1.1
295                 if (devices[i]->deviceVersionMajor < 1 ||
296                         (devices[i]->deviceVersionMajor == 1 && devices[i]->deviceVersionMinor < 1))
297                 {
298                     std::cerr << "Skip unsupported version of OpenCL device: " << devices[i]->deviceName
299                             << "(" << devices[i]->platform->platformName << ")" << std::endl;
300                     continue; // unsupported version of device, skip it
301                 }
302                 try
303                 {
304                     setDevice(devices[i]);
305                 }
306                 catch (...)
307                 {
308                     std::cerr << "ERROR: Can't select OpenCL device: " << devices[i]->deviceName
309                             << "(" << devices[i]->platform->platformName << ")" << std::endl;
310                     goto not_found;
311                 }
312                 return true;
313             }
314         }
315     }
316 not_found:
317     std::cerr << "ERROR: Required OpenCL device not found, check configuration: " << (configuration == NULL ? "" : configuration) << std::endl
318             << "    Platform: " << (platform.length() == 0 ? "any" : platform) << std::endl
319             << "    Device types: ";
320     for (size_t t = 0; t < deviceTypes.size(); t++)
321     {
322         std::cerr << deviceTypes[t] << " ";
323     }
324     std::cerr << std::endl << "    Device name: " << (deviceName.length() == 0 ? "any" : deviceName) << std::endl;
325     return false;
326 }
327
328 static cv::Mutex __initializedMutex;
329 static bool __initialized = false;
330 static int initializeOpenCLDevices()
331 {
332     assert(!__initialized);
333     __initialized = true;
334
335     assert(global_devices.size() == 0);
336
337     std::vector<cl::Platform> platforms;
338     try
339     {
340         openCLSafeCall(cl::Platform::get(&platforms));
341     }
342     catch (cv::Exception& e)
343     {
344         return 0; // OpenCL not found
345     }
346
347     global_platforms.resize(platforms.size());
348
349     for (size_t i = 0; i < platforms.size(); ++i)
350     {
351         PlatformInfoImpl& platformInfo = global_platforms[i];
352         platformInfo.info._id = i;
353
354         cl::Platform& platform = platforms[i];
355
356         platformInfo.platform_id = platform();
357         openCLSafeCall(platform.getInfo(CL_PLATFORM_PROFILE, &platformInfo.info.platformProfile));
358         openCLSafeCall(platform.getInfo(CL_PLATFORM_VERSION, &platformInfo.info.platformVersion));
359         openCLSafeCall(platform.getInfo(CL_PLATFORM_NAME, &platformInfo.info.platformName));
360         openCLSafeCall(platform.getInfo(CL_PLATFORM_VENDOR, &platformInfo.info.platformVendor));
361         openCLSafeCall(platform.getInfo(CL_PLATFORM_EXTENSIONS, &platformInfo.info.platformExtensons));
362
363         parseOpenCLVersion(platformInfo.info.platformVersion,
364                 platformInfo.info.platformVersionMajor, platformInfo.info.platformVersionMinor);
365
366         std::vector<cl::Device> devices;
367         cl_int status = platform.getDevices(CL_DEVICE_TYPE_ALL, &devices);
368         if(status != CL_DEVICE_NOT_FOUND)
369             openCLVerifyCall(status);
370
371         if(devices.size() > 0)
372         {
373             int baseIndx = global_devices.size();
374             global_devices.resize(baseIndx + devices.size());
375             platformInfo.deviceIDs.resize(devices.size());
376             platformInfo.info.devices.resize(devices.size());
377
378             for(size_t j = 0; j < devices.size(); ++j)
379             {
380                 cl::Device& device = devices[j];
381
382                 DeviceInfoImpl& deviceInfo = global_devices[baseIndx + j];
383                 deviceInfo.info._id = baseIndx + j;
384                 deviceInfo.platform_id = platform();
385                 deviceInfo.device_id = device();
386
387                 deviceInfo.info.platform = &platformInfo.info;
388                 platformInfo.deviceIDs[j] = deviceInfo.info._id;
389
390                 cl_device_type type = cl_device_type(-1);
391                 openCLSafeCall(device.getInfo(CL_DEVICE_TYPE, &type));
392                 deviceInfo.info.deviceType = DeviceType(type);
393
394                 openCLSafeCall(device.getInfo(CL_DEVICE_PROFILE, &deviceInfo.info.deviceProfile));
395                 openCLSafeCall(device.getInfo(CL_DEVICE_VERSION, &deviceInfo.info.deviceVersion));
396                 openCLSafeCall(device.getInfo(CL_DEVICE_NAME, &deviceInfo.info.deviceName));
397                 openCLSafeCall(device.getInfo(CL_DEVICE_VENDOR, &deviceInfo.info.deviceVendor));
398                 cl_uint vendorID = 0;
399                 openCLSafeCall(device.getInfo(CL_DEVICE_VENDOR_ID, &vendorID));
400                 deviceInfo.info.deviceVendorId = vendorID;
401                 openCLSafeCall(device.getInfo(CL_DRIVER_VERSION, &deviceInfo.info.deviceDriverVersion));
402                 openCLSafeCall(device.getInfo(CL_DEVICE_EXTENSIONS, &deviceInfo.info.deviceExtensions));
403
404                 parseOpenCLVersion(deviceInfo.info.deviceVersion,
405                         deviceInfo.info.deviceVersionMajor, deviceInfo.info.deviceVersionMinor);
406
407                 size_t maxWorkGroupSize = 0;
408                 openCLSafeCall(device.getInfo(CL_DEVICE_MAX_WORK_GROUP_SIZE, &maxWorkGroupSize));
409                 deviceInfo.info.maxWorkGroupSize = maxWorkGroupSize;
410
411                 cl_uint maxDimensions = 0;
412                 openCLSafeCall(device.getInfo(CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, &maxDimensions));
413                 std::vector<size_t> maxWorkItemSizes(maxDimensions);
414                 openCLSafeCall(clGetDeviceInfo(device(), CL_DEVICE_MAX_WORK_ITEM_SIZES, sizeof(size_t) * maxDimensions,
415                         (void *)&maxWorkItemSizes[0], 0));
416                 deviceInfo.info.maxWorkItemSizes = maxWorkItemSizes;
417
418                 cl_uint maxComputeUnits = 0;
419                 openCLSafeCall(device.getInfo(CL_DEVICE_MAX_COMPUTE_UNITS, &maxComputeUnits));
420                 deviceInfo.info.maxComputeUnits = maxComputeUnits;
421
422                 cl_ulong localMemorySize = 0;
423                 openCLSafeCall(device.getInfo(CL_DEVICE_LOCAL_MEM_SIZE, &localMemorySize));
424                 deviceInfo.info.localMemorySize = (size_t)localMemorySize;
425
426
427                 cl_bool unifiedMemory = false;
428                 openCLSafeCall(device.getInfo(CL_DEVICE_HOST_UNIFIED_MEMORY, &unifiedMemory));
429                 deviceInfo.info.isUnifiedMemory = unifiedMemory != 0;
430
431                 //initialize extra options for compilation. Currently only fp64 is included.
432                 //Assume 4KB is enough to store all possible extensions.
433                 openCLSafeCall(device.getInfo(CL_DEVICE_EXTENSIONS, &deviceInfo.info.deviceExtensions));
434
435                 size_t fp64_khr = deviceInfo.info.deviceExtensions.find("cl_khr_fp64");
436                 if(fp64_khr != std::string::npos)
437                 {
438                     deviceInfo.info.compilationExtraOptions += "-D DOUBLE_SUPPORT";
439                     deviceInfo.info.haveDoubleSupport = true;
440                 }
441                 else
442                 {
443                     deviceInfo.info.haveDoubleSupport = false;
444                 }
445             }
446         }
447     }
448
449     for (size_t i = 0; i < platforms.size(); ++i)
450     {
451         PlatformInfoImpl& platformInfo = global_platforms[i];
452         for(size_t j = 0; j < platformInfo.deviceIDs.size(); ++j)
453         {
454             DeviceInfoImpl& deviceInfo = global_devices[platformInfo.deviceIDs[j]];
455             platformInfo.info.devices[j] = &deviceInfo.info;
456         }
457     }
458
459     return global_devices.size();
460 }
461
462
463 DeviceInfo::DeviceInfo()
464     : _id(-1), deviceType(DeviceType(0)),
465       deviceVendorId(-1),
466       maxWorkGroupSize(0), maxComputeUnits(0), localMemorySize(0),
467       deviceVersionMajor(0), deviceVersionMinor(0),
468       haveDoubleSupport(false), isUnifiedMemory(false),
469       platform(NULL)
470 {
471     // nothing
472 }
473
474 PlatformInfo::PlatformInfo()
475     : _id(-1),
476       platformVersionMajor(0), platformVersionMinor(0)
477 {
478     // nothing
479 }
480
481 //////////////////////////////// OpenCL context ////////////////////////
482 //This is a global singleton class used to represent a OpenCL context.
483 class ContextImpl : public Context
484 {
485 public:
486     const cl_device_id clDeviceID;
487     cl_context clContext;
488     cl_command_queue clCmdQueue;
489     const DeviceInfo& deviceInfo;
490
491 protected:
492     ContextImpl(const DeviceInfo& deviceInfo, cl_device_id clDeviceID)
493         : clDeviceID(clDeviceID), clContext(NULL), clCmdQueue(NULL), deviceInfo(deviceInfo)
494     {
495         // nothing
496     }
497     ~ContextImpl();
498 public:
499     static void setContext(const DeviceInfo* deviceInfo);
500
501     bool supportsFeature(FEATURE_TYPE featureType) const;
502
503     static void cleanupContext(void);
504 };
505
506 static cv::Mutex currentContextMutex;
507 static ContextImpl* currentContext = NULL;
508
509 Context* Context::getContext()
510 {
511     if (currentContext == NULL)
512     {
513         if (!__initialized || !__deviceSelected)
514         {
515             cv::AutoLock lock(__initializedMutex);
516             if (!__initialized)
517             {
518                 if (initializeOpenCLDevices() == 0)
519                 {
520                     CV_Error(CV_OpenCLInitError, "OpenCL not available");
521                 }
522             }
523             if (!__deviceSelected)
524             {
525                 if (!selectOpenCLDevice())
526                 {
527                     CV_Error(CV_OpenCLInitError, "Can't select OpenCL device");
528                 }
529             }
530         }
531         CV_Assert(currentContext != NULL);
532     }
533     return currentContext;
534 }
535
536 bool Context::supportsFeature(FEATURE_TYPE featureType) const
537 {
538     return ((ContextImpl*)this)->supportsFeature(featureType);
539 }
540
541 const DeviceInfo& Context::getDeviceInfo() const
542 {
543     return ((ContextImpl*)this)->deviceInfo;
544 }
545
546 const void* Context::getOpenCLContextPtr() const
547 {
548     return &(((ContextImpl*)this)->clContext);
549 }
550
551 const void* Context::getOpenCLCommandQueuePtr() const
552 {
553     return &(((ContextImpl*)this)->clCmdQueue);
554 }
555
556 const void* Context::getOpenCLDeviceIDPtr() const
557 {
558     return &(((ContextImpl*)this)->clDeviceID);
559 }
560
561
562 bool ContextImpl::supportsFeature(FEATURE_TYPE featureType) const
563 {
564     switch (featureType)
565     {
566     case FEATURE_CL_DOUBLE:
567         return deviceInfo.haveDoubleSupport;
568     case FEATURE_CL_UNIFIED_MEM:
569         return deviceInfo.isUnifiedMemory;
570     case FEATURE_CL_VER_1_2:
571         return deviceInfo.deviceVersionMajor > 1 || (deviceInfo.deviceVersionMajor == 1 && deviceInfo.deviceVersionMinor >= 2);
572     }
573     CV_Error(CV_StsBadArg, "Invalid feature type");
574     return false;
575 }
576
577 #if defined(WIN32)
578 static bool __termination = false;
579 #endif
580
581 ContextImpl::~ContextImpl()
582 {
583 #ifdef WIN32
584     // if process is on termination stage (ExitProcess was called and other threads were terminated)
585     // then disable command queue release because it may cause program hang
586     if (!__termination)
587 #endif
588     {
589         if(clCmdQueue)
590         {
591             openCLSafeCall(clReleaseCommandQueue(clCmdQueue)); // some cleanup problems are here
592         }
593
594         if(clContext)
595         {
596             openCLSafeCall(clReleaseContext(clContext));
597         }
598     }
599     clCmdQueue = NULL;
600     clContext = NULL;
601 }
602
603 void fft_teardown();
604 void clBlasTeardown();
605
606 void ContextImpl::cleanupContext(void)
607 {
608     fft_teardown();
609     clBlasTeardown();
610
611     cv::AutoLock lock(currentContextMutex);
612     if (currentContext)
613         delete currentContext;
614     currentContext = NULL;
615 }
616
617 void ContextImpl::setContext(const DeviceInfo* deviceInfo)
618 {
619     CV_Assert(deviceInfo->_id >= 0 && deviceInfo->_id < (int)global_devices.size());
620
621     {
622         cv::AutoLock lock(currentContextMutex);
623         if (currentContext)
624         {
625             if (currentContext->deviceInfo._id == deviceInfo->_id)
626                 return;
627         }
628     }
629
630     DeviceInfoImpl& infoImpl = global_devices[deviceInfo->_id];
631     CV_Assert(deviceInfo == &infoImpl.info);
632
633     cl_int status = 0;
634     cl_context_properties cps[3] = { CL_CONTEXT_PLATFORM, (cl_context_properties)(infoImpl.platform_id), 0 };
635     cl_context clContext = clCreateContext(cps, 1, &infoImpl.device_id, NULL, NULL, &status);
636     openCLVerifyCall(status);
637     // TODO add CL_QUEUE_PROFILING_ENABLE
638     cl_command_queue clCmdQueue = clCreateCommandQueue(clContext, infoImpl.device_id, 0, &status);
639     openCLVerifyCall(status);
640
641     ContextImpl* ctx = new ContextImpl(infoImpl.info, infoImpl.device_id);
642     ctx->clCmdQueue = clCmdQueue;
643     ctx->clContext = clContext;
644
645     ContextImpl* old = NULL;
646     {
647         cv::AutoLock lock(currentContextMutex);
648         old = currentContext;
649         currentContext = ctx;
650     }
651     if (old != NULL)
652     {
653         delete old;
654     }
655 }
656
657 int getOpenCLPlatforms(PlatformsInfo& platforms)
658 {
659     if (!__initialized)
660         initializeOpenCLDevices();
661
662     platforms.clear();
663
664     for (size_t id = 0; id < global_platforms.size(); ++id)
665     {
666         PlatformInfoImpl& impl = global_platforms[id];
667         platforms.push_back(&impl.info);
668     }
669
670     return platforms.size();
671 }
672
673 int getOpenCLDevices(std::vector<const DeviceInfo*> &devices, int deviceType, const PlatformInfo* platform)
674 {
675     if (!__initialized)
676         initializeOpenCLDevices();
677
678     devices.clear();
679
680     switch(deviceType)
681     {
682     case CVCL_DEVICE_TYPE_DEFAULT:
683     case CVCL_DEVICE_TYPE_CPU:
684     case CVCL_DEVICE_TYPE_GPU:
685     case CVCL_DEVICE_TYPE_ACCELERATOR:
686     case CVCL_DEVICE_TYPE_ALL:
687         break;
688     default:
689         return 0;
690     }
691
692     if (platform == NULL)
693     {
694         for (size_t id = 0; id < global_devices.size(); ++id)
695         {
696             DeviceInfoImpl& deviceInfo = global_devices[id];
697             if (((int)deviceInfo.info.deviceType & deviceType) != 0)
698             {
699                 devices.push_back(&deviceInfo.info);
700             }
701         }
702     }
703     else
704     {
705         for (size_t id = 0; id < platform->devices.size(); ++id)
706         {
707             const DeviceInfo* deviceInfo = platform->devices[id];
708             if (((int)deviceInfo->deviceType & deviceType) == deviceType)
709             {
710                 devices.push_back(deviceInfo);
711             }
712         }
713     }
714
715     return (int)devices.size();
716 }
717
718 void setDevice(const DeviceInfo* info)
719 {
720     if (!__deviceSelected)
721         __deviceSelected = true;
722
723     ContextImpl::setContext(info);
724 }
725
726 bool supportsFeature(FEATURE_TYPE featureType)
727 {
728     return Context::getContext()->supportsFeature(featureType);
729 }
730
731 struct __Module
732 {
733     __Module() { /* moved to Context::getContext(): initializeOpenCLDevices(); */ }
734     ~__Module() { ContextImpl::cleanupContext(); }
735 };
736 static __Module __module;
737
738
739 } // namespace ocl
740 } // namespace cv
741
742
743 #if defined(WIN32) && defined(CVAPI_EXPORTS)
744
745 extern "C"
746 BOOL WINAPI DllMain(HINSTANCE /*hInst*/, DWORD fdwReason, LPVOID lpReserved)
747 {
748     if (fdwReason == DLL_PROCESS_DETACH)
749     {
750         if (lpReserved != NULL) // called after ExitProcess() call
751             cv::ocl::__termination = true;
752     }
753     return TRUE;
754 }
755
756 #endif