用OpenCV去处理图像的时候,为了提高效率会使用UMat去处理。
UMat会调用OpenCL。但由于系统环境设置原因,可能一直会调用集成显卡。
查看ocl.cpp源码后发现有下列方法。其中主要关注getenv,调用系统环境。
static cl_device_id selectOpenCLDevice()
{
std::string platform, deviceName;
std::vector deviceTypes;
const char* configuration = getenv("OPENCV_OPENCL_DEVICE");
if (configuration &&
(strcmp(configuration, "disabled") == 0 ||
!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());
if (deviceID < 0)
return NULL;
}
}
std::vector platforms;
{
cl_uint numPlatforms = 0;
CV_OCL_DBG_CHECK(clGetPlatformIDs(0, NULL, &numPlatforms));
if (numPlatforms == 0)
return NULL;
platforms.resize((size_t)numPlatforms);
CV_OCL_DBG_CHECK(clGetPlatformIDs(numPlatforms, &platforms[0], &numPlatforms));
platforms.resize(numPlatforms);
}
int selectedPlatform = -1;
if (platform.length() > 0)
{
for (size_t i = 0; i < platforms.size(); i++)
{
std::string name;
CV_OCL_DBG_CHECK(getStringInfo(clGetPlatformInfo, platforms[i], CL_PLATFORM_NAME, name));
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");
if (configuration)
deviceTypes.push_back("CPU");
}
else
deviceTypes.push_back("ALL");
}
for (size_t t = 0; t < deviceTypes.size(); t++)
{
int deviceType = 0;
std::string tempStrDeviceType = deviceTypes[t];
std::transform(tempStrDeviceType.begin(), tempStrDeviceType.end(), tempStrDeviceType.begin(), char_tolower);
if (tempStrDeviceType == "gpu" || tempStrDeviceType == "dgpu" || tempStrDeviceType == "igpu")
deviceType = Device::TYPE_GPU;
else if (tempStrDeviceType == "cpu")
deviceType = Device::TYPE_CPU;
else if (tempStrDeviceType == "accelerator")
deviceType = Device::TYPE_ACCELERATOR;
else if (tempStrDeviceType == "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 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;
cl_int status = clGetDeviceIDs(platforms[i], deviceType, 0, NULL, &count);
if (!(status == CL_SUCCESS || status == CL_DEVICE_NOT_FOUND))
{
CV_OCL_DBG_CHECK_RESULT(status, "clGetDeviceIDs get count");
}
if (count == 0)
continue;
size_t base = devices.size();
devices.resize(base + count);
status = clGetDeviceIDs(platforms[i], deviceType, count, &devices[base], &count);
if (!(status == CL_SUCCESS || status == CL_DEVICE_NOT_FOUND))
{
CV_OCL_DBG_CHECK_RESULT(status, "clGetDeviceIDs get IDs");
}
}
for (size_t i = (isID ? deviceID : 0);
(isID ? (i == (size_t)deviceID) : true) && (i < devices.size());
i++)
{
std::string name;
CV_OCL_DBG_CHECK(getStringInfo(clGetDeviceInfo, devices[i], CL_DEVICE_NAME, name));
cl_bool useGPU = true;
if(tempStrDeviceType == "dgpu" || tempStrDeviceType == "igpu")
{
cl_bool isIGPU = CL_FALSE;
CV_OCL_DBG_CHECK(clGetDeviceInfo(devices[i], CL_DEVICE_HOST_UNIFIED_MEMORY, sizeof(isIGPU), &isIGPU, NULL));
useGPU = tempStrDeviceType == "dgpu" ? !isIGPU : isIGPU;
}
if ( (isID || name.find(deviceName) != std::string::npos) && useGPU)
{
// TODO check for OpenCL 1.1
return devices[i];
}
}
}
not_found:
if (!configuration)
return NULL; // suppress messages on stderr
std::cerr << "ERROR: Requested OpenCL device not found, check configuration: " << 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;
}
如果想要调用nvidia gpu, 最容易的方法,只需如下配置即可:
set OPENCV_OPENCL_DEVICE=NVIDIA:GPU:0
具体含义可以查看以下代码:
// Layout: ::
// Sample: AMD:GPU:
// Sample: AMD:GPU:Tahiti
// Sample: :GPU|CPU: = '' = ':' = '::'
static bool parseOpenCLDeviceConfiguration(const std::string& configurationStr,
std::string& platform, std::vector& deviceTypes, std::string& deviceNameOrID)
{
std::vector parts;
split(configurationStr, ':', parts);
if (parts.size() > 3)
{
std::cerr << "ERROR: Invalid configuration string for OpenCL device" << std::endl;
return false;
}
if (parts.size() > 2)
deviceNameOrID = parts[2];
if (parts.size() > 1)
{
split(parts[1], '|', deviceTypes);
}
if (parts.size() > 0)
{
platform = parts[0];
}
return true;
}