#include "EmberCLPch.h"
#include "OpenCLInfo.h"
namespace EmberCLns
{
///
/// Initialize the all platforms and devices and keep information about them in lists.
///
OpenCLInfo::OpenCLInfo()
{
cl_int err;
vector platforms;
vector> devices;
intmax_t workingPlatformIndex = -1;
m_Init = false;
cl::Platform::get(&platforms);
devices.resize(platforms.size());
m_Platforms.reserve(platforms.size());
m_Devices.reserve(platforms.size());
m_DeviceNames.reserve(platforms.size());
m_AllDeviceNames.reserve(platforms.size());
m_DeviceIndices.reserve(platforms.size());
for (size_t i = 0; i < platforms.size(); i++)
platforms[i].getDevices(CL_DEVICE_TYPE_ALL, &devices[i]);
for (size_t platform = 0; platform < platforms.size(); platform++)
{
bool platformOk = false;
bool deviceOk = false;
cl::Context context;
if (CreateContext(platforms[platform], context, false))//Platform is ok, now do context. Unshared by default.
{
size_t workingDeviceIndex = 0;
for (size_t device = 0; device < devices[platform].size(); device++)//Context is ok, now do devices.
{
auto q = cl::CommandQueue(context, devices[platform][device], 0, &err);//At least one GPU device is present, so create a command queue.
if (CheckCL(err, "cl::CommandQueue()"))
{
if (!platformOk)
{
m_Platforms.push_back(platforms[platform]);
m_PlatformNames.push_back(platforms[platform].getInfo(nullptr) + " " + platforms[platform].getInfo(nullptr) + " " + platforms[platform].getInfo(nullptr));
workingPlatformIndex++;
platformOk = true;
}
if (!deviceOk)
{
m_Devices.push_back(vector());
m_DeviceNames.push_back(vector());
m_Devices.back().reserve(devices[platform].size());
m_DeviceNames.back().reserve(devices[platform].size());
deviceOk = true;
}
m_Devices.back().push_back(devices[platform][device]);
m_DeviceNames.back().push_back(devices[platform][device].getInfo(nullptr) + " " + devices[platform][device].getInfo(nullptr));// + " " + devices[platform][device].getInfo());
m_AllDeviceNames.push_back(m_DeviceNames.back().back());
m_DeviceIndices.push_back(pair(workingPlatformIndex, workingDeviceIndex++));
m_Init = true;//If at least one platform and device succeeded, OpenCL is ok. It's now ok to begin building and running programs.
}
}
}
}
}
///
/// Get a const reference to the vector of available platforms.
///
/// A const reference to the vector of available platforms
const vector& OpenCLInfo::Platforms() const
{
return m_Platforms;
}
///
/// Get a const reference to the platform name at the specified index.
///
/// The platform index to get the name of
/// The platform name if found, else empty string
const string& OpenCLInfo::PlatformName(size_t platform) const
{
static string s;
return platform < m_PlatformNames.size() ? m_PlatformNames[platform] : s;
}
///
/// Get a const reference to a vector of all available platform names on the system as a vector of strings.
///
/// All available platform names on the system as a vector of strings
const vector& OpenCLInfo::PlatformNames() const
{
return m_PlatformNames;
}
///
/// Get a const reference to a vector of vectors of all available devices on the system.
/// Each outer vector is a different platform.
///
/// All available devices on the system, grouped by platform.
const vector>& OpenCLInfo::Devices() const
{
return m_Devices;
}
///
/// Get a const reference to the device name at the specified index on the platform
/// at the specified index.
///
/// The platform index of the device
/// The device index
/// The name of the device if found, else empty string
const string& OpenCLInfo::DeviceName(size_t platform, size_t device) const
{
static string s;
if (platform < m_Platforms.size() && platform < m_Devices.size())
if (device < m_Devices[platform].size())
return m_DeviceNames[platform][device];
return s;
}
///
/// Get a const reference to a vector of pairs of uints which contain the platform,device
/// indices of all available devices on the system.
///
/// All available devices on the system as platform,device index pairs
const vector>& OpenCLInfo::DeviceIndices() const
{
return m_DeviceIndices;
}
///
/// Get a const reference to a vector of all available device names on the system as a vector of strings.
///
/// All available device names on the system as a vector of strings
const vector& OpenCLInfo::AllDeviceNames() const
{
return m_AllDeviceNames;
}
///
/// Get a const reference to a vector of all available device names on the platform
/// at the specified index as a vector of strings.
///
/// The platform index whose devices names will be returned
/// All available device names on the platform at the specified index as a vector of strings if within range, else empty vector.
const vector& OpenCLInfo::DeviceNames(size_t platform) const
{
static vector v;
if (platform < m_DeviceNames.size())
return m_DeviceNames[platform];
return v;
}
///
/// Get the total device index at the specified platform and device index.
///
/// The platform index of the device
/// The device index within the platform
/// The total device index if found, else 0
size_t OpenCLInfo::TotalDeviceIndex(size_t platform, size_t device) const
{
size_t index = 0;
pair p{ platform, device };
for (size_t i = 0; i < m_DeviceIndices.size(); i++)
{
if (p == m_DeviceIndices[i])
{
index = i;
break;
}
}
return index;
}
///
/// Create a context that is optionally shared with OpenGL and place it in the
/// passed in context ref parameter.
///
/// The platform object to create the context on
/// The context object to store the result in
/// True if shared with OpenGL, else not shared.
/// True if success, else false.
bool OpenCLInfo::CreateContext(const cl::Platform& platform, cl::Context& context, bool shared)
{
cl_int err;
if (shared)
{
//Define OS-specific context properties and create the OpenCL context.
#if defined (__APPLE__) || defined(MACOSX)
CGLContextObj kCGLContext = CGLGetCurrentContext();
CGLShareGroupObj kCGLShareGroup = CGLGetShareGroup(kCGLContext);
cl_context_properties props[] =
{
CL_CONTEXT_PROPERTY_USE_CGL_SHAREGROUP_APPLE, (cl_context_properties)kCGLShareGroup,
0
};
context = cl::Context(CL_DEVICE_TYPE_GPU, props, nullptr, nullptr, &err);//May need to tinker with this on Mac.
#else
#if defined WIN32
cl_context_properties props[] =
{
CL_GL_CONTEXT_KHR, (cl_context_properties)wglGetCurrentContext(),
CL_WGL_HDC_KHR, (cl_context_properties)wglGetCurrentDC(),
CL_CONTEXT_PLATFORM, reinterpret_cast((platform)()),
0
};
context = cl::Context(CL_DEVICE_TYPE_GPU, props, nullptr, nullptr, &err);
#else
cl_context_properties props[] =
{
CL_GL_CONTEXT_KHR, cl_context_properties(glXGetCurrentContext()),
CL_GLX_DISPLAY_KHR, cl_context_properties(glXGetCurrentDisplay()),
CL_CONTEXT_PLATFORM, reinterpret_cast((platform)()),
0
};
context = cl::Context(CL_DEVICE_TYPE_GPU, props, nullptr, nullptr, &err);
#endif
#endif
}
else
{
cl_context_properties props[3] =
{
CL_CONTEXT_PLATFORM,
reinterpret_cast((platform)()),
0
};
context = cl::Context(CL_DEVICE_TYPE_ALL, props, nullptr, nullptr, &err);
}
return CheckCL(err, "cl::Context()");
}
///
/// Return whether at least one device has been found and properly initialized.
///
/// True if success, else false.
bool OpenCLInfo::Ok() const
{
return m_Init;
}
///
/// Get all information about all platforms and devices.
///
/// A string with all information about all platforms and devices
string OpenCLInfo::DumpInfo() const
{
ostringstream os;
vector sizes;
os.imbue(locale(""));
for (size_t platform = 0; platform < m_Platforms.size(); platform++)
{
os << "Platform " << platform << ": " << PlatformName(platform) << "\n";
for (size_t device = 0; device < m_Devices[platform].size(); device++)
{
os << "Device " << device << ": " << DeviceName(platform, device);
os << "\nCL_DEVICE_OPENCL_C_VERSION: " << GetInfo(platform, device, CL_DEVICE_OPENCL_C_VERSION);
os << "\nCL_DEVICE_LOCAL_MEM_SIZE: " << GetInfo(platform, device, CL_DEVICE_LOCAL_MEM_SIZE);
os << "\nCL_DEVICE_LOCAL_MEM_TYPE: " << GetInfo(platform, device, CL_DEVICE_LOCAL_MEM_TYPE);
os << "\nCL_DEVICE_MAX_COMPUTE_UNITS: " << GetInfo(platform, device, CL_DEVICE_MAX_COMPUTE_UNITS);
os << "\nCL_DEVICE_MAX_READ_IMAGE_ARGS: " << GetInfo(platform, device, CL_DEVICE_MAX_READ_IMAGE_ARGS);
os << "\nCL_DEVICE_MAX_WRITE_IMAGE_ARGS: " << GetInfo(platform, device, CL_DEVICE_MAX_WRITE_IMAGE_ARGS);
os << "\nCL_DEVICE_MAX_MEM_ALLOC_SIZE: " << GetInfo(platform, device, CL_DEVICE_MAX_MEM_ALLOC_SIZE);
os << "\nCL_DEVICE_ADDRESS_BITS: " << GetInfo(platform, device, CL_DEVICE_ADDRESS_BITS);
os << "\nCL_DEVICE_GLOBAL_MEM_CACHE_TYPE: " << GetInfo(platform, device, CL_DEVICE_GLOBAL_MEM_CACHE_TYPE);
os << "\nCL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE: " << GetInfo(platform, device, CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE);
os << "\nCL_DEVICE_GLOBAL_MEM_CACHE_SIZE: " << GetInfo(platform, device, CL_DEVICE_GLOBAL_MEM_CACHE_SIZE);
os << "\nCL_DEVICE_GLOBAL_MEM_SIZE: " << GetInfo(platform, device, CL_DEVICE_GLOBAL_MEM_SIZE);
os << "\nCL_DEVICE_MAX_CONSTANT_BUFFER_SIZE: " << GetInfo(platform, device, CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE);
os << "\nCL_DEVICE_MAX_CONSTANT_ARGS: " << GetInfo(platform, device, CL_DEVICE_MAX_CONSTANT_ARGS);
os << "\nCL_DEVICE_MAX_WORK_ITEM_DIMENSIONS: " << GetInfo(platform, device, CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS);
os << "\nCL_DEVICE_MAX_WORK_GROUP_SIZE: " << GetInfo(platform, device, CL_DEVICE_MAX_WORK_GROUP_SIZE);
sizes = GetInfo>(platform, device, CL_DEVICE_MAX_WORK_ITEM_SIZES);
os << "\nCL_DEVICE_MAX_WORK_ITEM_SIZES: " << sizes[0] << ", " << sizes[1] << ", " << sizes[2] << "\n" << "\n";
if (device != m_Devices[platform].size() - 1 && platform != m_Platforms.size() - 1)
os << "\n";
}
os << "\n";
}
return os.str();
}
///
/// Check an OpenCL return value for errors.
///
/// The error code to inspect
/// A description of where the value was gotten from
/// True if success, else false.
bool OpenCLInfo::CheckCL(cl_int err, const char* name)
{
if (err != CL_SUCCESS)
{
ostringstream ss;
ss << "ERROR: " << ErrorToStringCL(err) << " in " << name << ".\n";
AddToReport(ss.str());
}
return err == CL_SUCCESS;
}
///
/// Translate an OpenCL error code into a human readable string.
///
/// The error code to translate
/// A human readable description of the error passed in
string OpenCLInfo::ErrorToStringCL(cl_int err)
{
switch (err)
{
case CL_SUCCESS: return "Success";
case CL_DEVICE_NOT_FOUND: return "Device not found";
case CL_DEVICE_NOT_AVAILABLE: return "Device not available";
case CL_COMPILER_NOT_AVAILABLE: return "Compiler not available";
case CL_MEM_OBJECT_ALLOCATION_FAILURE: return "Memory object allocation failure";
case CL_OUT_OF_RESOURCES: return "Out of resources";
case CL_OUT_OF_HOST_MEMORY: return "Out of host memory";
case CL_PROFILING_INFO_NOT_AVAILABLE: return "Profiling information not available";
case CL_MEM_COPY_OVERLAP: return "Memory copy overlap";
case CL_IMAGE_FORMAT_MISMATCH: return "Image format mismatch";
case CL_IMAGE_FORMAT_NOT_SUPPORTED: return "Image format not supported";
case CL_BUILD_PROGRAM_FAILURE: return "Program build failure";
case CL_MAP_FAILURE: return "Map failure";
case CL_MISALIGNED_SUB_BUFFER_OFFSET: return "Misaligned sub buffer offset";
case CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST: return "Exec status error for events in wait list";
case CL_INVALID_VALUE: return "Invalid value";
case CL_INVALID_DEVICE_TYPE: return "Invalid device type";
case CL_INVALID_PLATFORM: return "Invalid platform";
case CL_INVALID_DEVICE: return "Invalid device";
case CL_INVALID_CONTEXT: return "Invalid context";
case CL_INVALID_QUEUE_PROPERTIES: return "Invalid queue properties";
case CL_INVALID_COMMAND_QUEUE: return "Invalid command queue";
case CL_INVALID_HOST_PTR: return "Invalid host pointer";
case CL_INVALID_MEM_OBJECT: return "Invalid memory object";
case CL_INVALID_IMAGE_FORMAT_DESCRIPTOR: return "Invalid image format descriptor";
case CL_INVALID_IMAGE_SIZE: return "Invalid image size";
case CL_INVALID_SAMPLER: return "Invalid sampler";
case CL_INVALID_BINARY: return "Invalid binary";
case CL_INVALID_BUILD_OPTIONS: return "Invalid build options";
case CL_INVALID_PROGRAM: return "Invalid program";
case CL_INVALID_PROGRAM_EXECUTABLE: return "Invalid program executable";
case CL_INVALID_KERNEL_NAME: return "Invalid kernel name";
case CL_INVALID_KERNEL_DEFINITION: return "Invalid kernel definition";
case CL_INVALID_KERNEL: return "Invalid kernel";
case CL_INVALID_ARG_INDEX: return "Invalid argument index";
case CL_INVALID_ARG_VALUE: return "Invalid argument value";
case CL_INVALID_ARG_SIZE: return "Invalid argument size";
case CL_INVALID_KERNEL_ARGS: return "Invalid kernel arguments";
case CL_INVALID_WORK_DIMENSION: return "Invalid work dimension";
case CL_INVALID_WORK_GROUP_SIZE: return "Invalid work group size";
case CL_INVALID_WORK_ITEM_SIZE: return "Invalid work item size";
case CL_INVALID_GLOBAL_OFFSET: return "Invalid global offset";
case CL_INVALID_EVENT_WAIT_LIST: return "Invalid event wait list";
case CL_INVALID_EVENT: return "Invalid event";
case CL_INVALID_OPERATION: return "Invalid operation";
case CL_INVALID_GL_OBJECT: return "Invalid OpenGL object";
case CL_INVALID_BUFFER_SIZE: return "Invalid buffer size";
case CL_INVALID_MIP_LEVEL: return "Invalid mip-map level";
case CL_INVALID_GLOBAL_WORK_SIZE: return "Invalid global work size";
case CL_INVALID_PROPERTY: return "Invalid property";
default:
{
ostringstream ss;
ss << " " << err;
return ss.str();
}
}
}
}