|
|
|
@ -41,6 +41,9 @@ |
|
|
|
|
|
|
|
|
|
#include "precomp.hpp" |
|
|
|
|
#include <map> |
|
|
|
|
#include <string> |
|
|
|
|
#include <sstream> |
|
|
|
|
#include <iostream> // std::cerr |
|
|
|
|
|
|
|
|
|
#include "opencv2/core/opencl/runtime/opencl_clamdblas.hpp" |
|
|
|
|
#include "opencv2/core/opencl/runtime/opencl_clamdfft.hpp" |
|
|
|
@ -1905,6 +1908,232 @@ const Device& Device::getDefault() |
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
template <typename Functor, typename ObjectType> |
|
|
|
|
inline cl_int getStringInfo(Functor f, ObjectType obj, cl_uint name, std::string& param) |
|
|
|
|
{ |
|
|
|
|
::size_t required; |
|
|
|
|
cl_int err = f(obj, name, 0, NULL, &required); |
|
|
|
|
if (err != CL_SUCCESS) |
|
|
|
|
return err; |
|
|
|
|
|
|
|
|
|
param.clear(); |
|
|
|
|
if (required > 0) |
|
|
|
|
{ |
|
|
|
|
std::vector<char> buf(required + 1, char(0)); |
|
|
|
|
err = f(obj, name, required, &buf[0], NULL); |
|
|
|
|
if (err != CL_SUCCESS) |
|
|
|
|
return err; |
|
|
|
|
param = &buf[0]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return CL_SUCCESS; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static void split(const std::string &s, char delim, std::vector<std::string> &elems) { |
|
|
|
|
std::stringstream ss(s); |
|
|
|
|
std::string item; |
|
|
|
|
while (std::getline(ss, item, delim)) { |
|
|
|
|
elems.push_back(item); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static std::vector<std::string> split(const std::string &s, char delim) { |
|
|
|
|
std::vector<std::string> elems; |
|
|
|
|
split(s, delim, elems); |
|
|
|
|
return elems; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Layout: <Platform>:<CPU|GPU|ACCELERATOR|nothing=GPU/CPU>:<deviceName>
|
|
|
|
|
// Sample: AMD:GPU:
|
|
|
|
|
// Sample: AMD:GPU:Tahiti
|
|
|
|
|
// Sample: :GPU|CPU: = '' = ':' = '::'
|
|
|
|
|
static bool parseOpenCLDeviceConfiguration(const std::string& configurationStr, |
|
|
|
|
std::string& platform, std::vector<std::string>& deviceTypes, std::string& deviceNameOrID) |
|
|
|
|
{ |
|
|
|
|
std::string deviceTypesStr; |
|
|
|
|
size_t p0 = configurationStr.find(':'); |
|
|
|
|
if (p0 != std::string::npos) |
|
|
|
|
{ |
|
|
|
|
size_t p1 = configurationStr.find(':', p0 + 1); |
|
|
|
|
if (p1 != std::string::npos) |
|
|
|
|
{ |
|
|
|
|
size_t p2 = configurationStr.find(':', p1 + 1); |
|
|
|
|
if (p2 != std::string::npos) |
|
|
|
|
{ |
|
|
|
|
std::cerr << "ERROR: Invalid configuration string for OpenCL device" << std::endl; |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
// assume platform + device types + device name/id
|
|
|
|
|
platform = configurationStr.substr(0, p0); |
|
|
|
|
deviceTypesStr = configurationStr.substr(p0 + 1, p1 - (p0 + 1)); |
|
|
|
|
deviceNameOrID = configurationStr.substr(p1 + 1, configurationStr.length() - (p1 + 1)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
// assume platform + device types
|
|
|
|
|
platform = configurationStr.substr(0, p0); |
|
|
|
|
deviceTypesStr = configurationStr.substr(p0 + 1, configurationStr.length() - (p0 + 1)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
// assume only platform
|
|
|
|
|
platform = configurationStr; |
|
|
|
|
} |
|
|
|
|
deviceTypes = split(deviceTypesStr, '|'); |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static cl_device_id selectOpenCLDevice() |
|
|
|
|
{ |
|
|
|
|
std::string platform; |
|
|
|
|
std::vector<std::string> deviceTypes; |
|
|
|
|
std::string deviceName; |
|
|
|
|
const char* configuration = getenv("OPENCV_OPENCL_DEVICE"); |
|
|
|
|
if (configuration) |
|
|
|
|
{ |
|
|
|
|
if (!parseOpenCLDeviceConfiguration(std::string(configuration), platform, deviceTypes, deviceName)) |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool isID = false; |
|
|
|
|
int deviceID = -1; |
|
|
|
|
if (deviceName.length() == 1) |
|
|
|
|
// We limit ID range to 0..9, because we want to write:
|
|
|
|
|
// - '2500' to mean i5-2500
|
|
|
|
|
// - '8350' to mean AMD FX-8350
|
|
|
|
|
// - '650' to mean GeForce 650
|
|
|
|
|
// To extend ID range change condition to '> 0'
|
|
|
|
|
{ |
|
|
|
|
isID = true; |
|
|
|
|
for (size_t i = 0; i < deviceName.length(); i++) |
|
|
|
|
{ |
|
|
|
|
if (!isdigit(deviceName[i])) |
|
|
|
|
{ |
|
|
|
|
isID = false; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (isID) |
|
|
|
|
{ |
|
|
|
|
deviceID = atoi(deviceName.c_str()); |
|
|
|
|
CV_Assert(deviceID >= 0); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
std::vector<cl_platform_id> platforms; |
|
|
|
|
cl_uint numPlatforms = 0; |
|
|
|
|
cl_int status = clGetPlatformIDs(0, NULL, &numPlatforms); |
|
|
|
|
CV_Assert(status == CL_SUCCESS); |
|
|
|
|
if (numPlatforms == 0) |
|
|
|
|
return NULL; |
|
|
|
|
platforms.resize((size_t)numPlatforms); |
|
|
|
|
status = clGetPlatformIDs(numPlatforms, &platforms[0], &numPlatforms); |
|
|
|
|
CV_Assert(status == CL_SUCCESS); |
|
|
|
|
|
|
|
|
|
int selectedPlatform = -1; |
|
|
|
|
if (platform.length() > 0) |
|
|
|
|
{ |
|
|
|
|
for (size_t i = 0; i < platforms.size(); i++) |
|
|
|
|
{ |
|
|
|
|
std::string name; |
|
|
|
|
status = getStringInfo(clGetPlatformInfo, platforms[i], CL_PLATFORM_NAME, name); |
|
|
|
|
CV_Assert(status == CL_SUCCESS); |
|
|
|
|
if (name.find(platform) != std::string::npos) |
|
|
|
|
{ |
|
|
|
|
selectedPlatform = (int)i; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (selectedPlatform == -1) |
|
|
|
|
{ |
|
|
|
|
std::cerr << "ERROR: Can't find OpenCL platform by name: " << platform << std::endl; |
|
|
|
|
goto not_found; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (deviceTypes.size() == 0) |
|
|
|
|
{ |
|
|
|
|
if (!isID) |
|
|
|
|
{ |
|
|
|
|
deviceTypes.push_back("GPU"); |
|
|
|
|
deviceTypes.push_back("CPU"); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
deviceTypes.push_back("ALL"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
for (size_t t = 0; t < deviceTypes.size(); t++) |
|
|
|
|
{ |
|
|
|
|
int deviceType = 0; |
|
|
|
|
if (deviceTypes[t] == "GPU") |
|
|
|
|
{ |
|
|
|
|
deviceType = Device::TYPE_GPU; |
|
|
|
|
} |
|
|
|
|
else if (deviceTypes[t] == "CPU") |
|
|
|
|
{ |
|
|
|
|
deviceType = Device::TYPE_CPU; |
|
|
|
|
} |
|
|
|
|
else if (deviceTypes[t] == "ACCELERATOR") |
|
|
|
|
{ |
|
|
|
|
deviceType = Device::TYPE_ACCELERATOR; |
|
|
|
|
} |
|
|
|
|
else if (deviceTypes[t] == "ALL") |
|
|
|
|
{ |
|
|
|
|
deviceType = Device::TYPE_ALL; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
std::cerr << "ERROR: Unsupported device type for OpenCL device (GPU, CPU, ACCELERATOR): " << deviceTypes[t] << std::endl; |
|
|
|
|
goto not_found; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
std::vector<cl_device_id> devices; // TODO Use clReleaseDevice to cleanup
|
|
|
|
|
for (int i = selectedPlatform >= 0 ? selectedPlatform : 0; |
|
|
|
|
(selectedPlatform >= 0 ? i == selectedPlatform : true) && (i < (int)platforms.size()); |
|
|
|
|
i++) |
|
|
|
|
{ |
|
|
|
|
cl_uint count = 0; |
|
|
|
|
status = clGetDeviceIDs(platforms[i], deviceType, 0, NULL, &count); |
|
|
|
|
CV_Assert(status == CL_SUCCESS || status == CL_DEVICE_NOT_FOUND); |
|
|
|
|
if (count == 0) |
|
|
|
|
continue; |
|
|
|
|
size_t base = devices.size(); |
|
|
|
|
devices.resize(base + count); |
|
|
|
|
status = clGetDeviceIDs(platforms[i], deviceType, count, &devices[base], &count); |
|
|
|
|
CV_Assert(status == CL_SUCCESS || status == CL_DEVICE_NOT_FOUND); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for (size_t i = (isID ? deviceID : 0); |
|
|
|
|
(isID ? (i == (size_t)deviceID) : true) && (i < devices.size()); |
|
|
|
|
i++) |
|
|
|
|
{ |
|
|
|
|
std::string name; |
|
|
|
|
status = getStringInfo(clGetDeviceInfo, devices[i], CL_DEVICE_NAME, name); |
|
|
|
|
CV_Assert(status == CL_SUCCESS); |
|
|
|
|
if (isID || name.find(deviceName) != std::string::npos) |
|
|
|
|
{ |
|
|
|
|
// TODO check for OpenCL 1.1
|
|
|
|
|
return devices[i]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
not_found: |
|
|
|
|
std::cerr << "ERROR: Required OpenCL device not found, check configuration: " << (configuration == NULL ? "" : configuration) << std::endl |
|
|
|
|
<< " Platform: " << (platform.length() == 0 ? "any" : platform) << std::endl |
|
|
|
|
<< " Device types: "; |
|
|
|
|
for (size_t t = 0; t < deviceTypes.size(); t++) |
|
|
|
|
{ |
|
|
|
|
std::cerr << deviceTypes[t] << " "; |
|
|
|
|
} |
|
|
|
|
std::cerr << std::endl << " Device name: " << (deviceName.length() == 0 ? "any" : deviceName) << std::endl; |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
struct Context2::Impl |
|
|
|
|
{ |
|
|
|
|
Impl() |
|
|
|
@ -1913,6 +2142,42 @@ struct Context2::Impl |
|
|
|
|
handle = 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void setDefault() |
|
|
|
|
{ |
|
|
|
|
CV_Assert(handle == NULL); |
|
|
|
|
|
|
|
|
|
cl_device_id d = selectOpenCLDevice(); |
|
|
|
|
|
|
|
|
|
if (d == NULL) |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
cl_platform_id pl = NULL; |
|
|
|
|
cl_int status = clGetDeviceInfo(d, CL_DEVICE_PLATFORM, sizeof(cl_platform_id), &pl, NULL); |
|
|
|
|
CV_Assert(status == CL_SUCCESS); |
|
|
|
|
|
|
|
|
|
cl_context_properties prop[] = |
|
|
|
|
{ |
|
|
|
|
CL_CONTEXT_PLATFORM, (cl_context_properties)pl, |
|
|
|
|
0 |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// !!! in the current implementation force the number of devices to 1 !!!
|
|
|
|
|
int nd = 1; |
|
|
|
|
|
|
|
|
|
handle = clCreateContext(prop, nd, &d, 0, 0, &status); |
|
|
|
|
CV_Assert(status == CL_SUCCESS); |
|
|
|
|
bool ok = handle != 0 && status >= 0; |
|
|
|
|
if( ok ) |
|
|
|
|
{ |
|
|
|
|
devices.resize(nd); |
|
|
|
|
devices[0].set(d); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
handle = NULL; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Impl(int dtype0) |
|
|
|
|
{ |
|
|
|
|
refcount = 1; |
|
|
|
@ -2022,6 +2287,21 @@ Context2::Context2(int dtype) |
|
|
|
|
create(dtype); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool Context2::create() |
|
|
|
|
{ |
|
|
|
|
if( !haveOpenCL() ) |
|
|
|
|
return false; |
|
|
|
|
if(p) |
|
|
|
|
p->release(); |
|
|
|
|
p = new Impl(); |
|
|
|
|
if(!p->handle) |
|
|
|
|
{ |
|
|
|
|
delete p; |
|
|
|
|
p = 0; |
|
|
|
|
} |
|
|
|
|
return p != 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool Context2::create(int dtype0) |
|
|
|
|
{ |
|
|
|
|
if( !haveOpenCL() ) |
|
|
|
@ -2081,23 +2361,16 @@ Context2& Context2::getDefault(bool initialize) |
|
|
|
|
static Context2 ctx; |
|
|
|
|
if(!ctx.p && haveOpenCL()) |
|
|
|
|
{ |
|
|
|
|
if (!ctx.p) |
|
|
|
|
ctx.p = new Impl(); |
|
|
|
|
if (initialize) |
|
|
|
|
{ |
|
|
|
|
// do not create new Context2 right away.
|
|
|
|
|
// First, try to retrieve existing context of the same type.
|
|
|
|
|
// In its turn, Platform::getContext() may call Context2::create()
|
|
|
|
|
// if there is no such context.
|
|
|
|
|
ctx.create(Device::TYPE_ACCELERATOR); |
|
|
|
|
if(!ctx.p) |
|
|
|
|
ctx.create(Device::TYPE_DGPU); |
|
|
|
|
if(!ctx.p) |
|
|
|
|
ctx.create(Device::TYPE_IGPU); |
|
|
|
|
if(!ctx.p) |
|
|
|
|
ctx.create(Device::TYPE_CPU); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
ctx.p = new Impl(); |
|
|
|
|
if (ctx.p->handle == NULL) |
|
|
|
|
ctx.p->setDefault(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|