#include "EmberCLPch.h" #include "OpenCLInfo.h" namespace EmberCLns { /// /// Initialize and return a reference to the one and only OpenCLInfo object. /// /// A reference to the only OpenCLInfo object. OpenCLInfo& OpenCLInfo::Instance() { static OpenCLInfo instance; return instance; } /// /// 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 plact 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) << endl; for (size_t device = 0; device < m_Devices[platform].size(); device++) { os << "Device " << device << ": " << DeviceName(platform, device) << endl; os << "CL_DEVICE_OPENCL_C_VERSION: " << GetInfo(platform, device, CL_DEVICE_OPENCL_C_VERSION) << endl; os << "CL_DEVICE_LOCAL_MEM_SIZE: " << GetInfo(platform, device, CL_DEVICE_LOCAL_MEM_SIZE) << endl; os << "CL_DEVICE_LOCAL_MEM_TYPE: " << GetInfo(platform, device, CL_DEVICE_LOCAL_MEM_TYPE) << endl; os << "CL_DEVICE_MAX_COMPUTE_UNITS: " << GetInfo(platform, device, CL_DEVICE_MAX_COMPUTE_UNITS) << endl; os << "CL_DEVICE_MAX_READ_IMAGE_ARGS: " << GetInfo(platform, device, CL_DEVICE_MAX_READ_IMAGE_ARGS) << endl; os << "CL_DEVICE_MAX_WRITE_IMAGE_ARGS: " << GetInfo(platform, device, CL_DEVICE_MAX_WRITE_IMAGE_ARGS) << endl; os << "CL_DEVICE_MAX_MEM_ALLOC_SIZE: " << GetInfo(platform, device, CL_DEVICE_MAX_MEM_ALLOC_SIZE) << endl; os << "CL_DEVICE_ADDRESS_BITS: " << GetInfo(platform, device, CL_DEVICE_ADDRESS_BITS) << endl; os << "CL_DEVICE_GLOBAL_MEM_CACHE_TYPE: " << GetInfo(platform, device, CL_DEVICE_GLOBAL_MEM_CACHE_TYPE) << endl; os << "CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE: " << GetInfo(platform, device, CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE) << endl; os << "CL_DEVICE_GLOBAL_MEM_CACHE_SIZE: " << GetInfo(platform, device, CL_DEVICE_GLOBAL_MEM_CACHE_SIZE) << endl; os << "CL_DEVICE_GLOBAL_MEM_SIZE: " << GetInfo(platform, device, CL_DEVICE_GLOBAL_MEM_SIZE) << endl; os << "CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE: " << GetInfo(platform, device, CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE) << endl; os << "CL_DEVICE_MAX_CONSTANT_ARGS: " << GetInfo(platform, device, CL_DEVICE_MAX_CONSTANT_ARGS) << endl; os << "CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS: " << GetInfo(platform, device, CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS) << endl; os << "CL_DEVICE_MAX_WORK_GROUP_SIZE: " << GetInfo(platform, device, CL_DEVICE_MAX_WORK_GROUP_SIZE) << endl; sizes = GetInfo>(platform, device, CL_DEVICE_MAX_WORK_ITEM_SIZES); os << "CL_DEVICE_MAX_WORK_ITEM_SIZES: " << sizes[0] << ", " << sizes[1] << ", " << sizes[2] << endl << endl; if (device != m_Devices[platform].size() - 1 && platform != m_Platforms.size() - 1) os << endl; } os << endl; } 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 << "." << endl; m_ErrorReport.push_back(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(); } } } }