2 * Copyright 2011-2013 Blender Foundation
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include "device/opencl/opencl.h"
21 #include "util/util_logging.h"
22 #include "util/util_md5.h"
23 #include "util/util_path.h"
24 #include "util/util_time.h"
31 OpenCLCache::Slot::ProgramEntry::ProgramEntry()
37 OpenCLCache::Slot::ProgramEntry::ProgramEntry(const ProgramEntry& rhs)
38 : program(rhs.program),
43 OpenCLCache::Slot::ProgramEntry::~ProgramEntry()
48 OpenCLCache::Slot::Slot()
49 : context_mutex(NULL),
54 OpenCLCache::Slot::Slot(const Slot& rhs)
55 : context_mutex(NULL),
57 programs(rhs.programs)
61 OpenCLCache::Slot::~Slot()
66 OpenCLCache& OpenCLCache::global_instance()
68 static OpenCLCache instance;
72 cl_context OpenCLCache::get_context(cl_platform_id platform,
74 thread_scoped_lock& slot_locker)
76 assert(platform != NULL);
78 OpenCLCache& self = global_instance();
80 thread_scoped_lock cache_lock(self.cache_lock);
82 pair<CacheMap::iterator,bool> ins = self.cache.insert(
83 CacheMap::value_type(PlatformDevicePair(platform, device), Slot()));
85 Slot &slot = ins.first->second;
87 /* create slot lock only while holding cache lock */
88 if(!slot.context_mutex)
89 slot.context_mutex = new thread_mutex;
91 /* need to unlock cache before locking slot, to allow store to complete */
95 slot_locker = thread_scoped_lock(*slot.context_mutex);
97 /* If the thing isn't cached */
98 if(slot.context == NULL) {
99 /* return with the caller's lock holder holding the slot lock */
103 /* the item was already cached, release the slot lock */
104 slot_locker.unlock();
106 cl_int ciErr = clRetainContext(slot.context);
107 assert(ciErr == CL_SUCCESS);
113 cl_program OpenCLCache::get_program(cl_platform_id platform,
116 thread_scoped_lock& slot_locker)
118 assert(platform != NULL);
120 OpenCLCache& self = global_instance();
122 thread_scoped_lock cache_lock(self.cache_lock);
124 pair<CacheMap::iterator,bool> ins = self.cache.insert(
125 CacheMap::value_type(PlatformDevicePair(platform, device), Slot()));
127 Slot &slot = ins.first->second;
129 pair<Slot::EntryMap::iterator,bool> ins2 = slot.programs.insert(
130 Slot::EntryMap::value_type(key, Slot::ProgramEntry()));
132 Slot::ProgramEntry &entry = ins2.first->second;
134 /* create slot lock only while holding cache lock */
136 entry.mutex = new thread_mutex;
138 /* need to unlock cache before locking slot, to allow store to complete */
142 slot_locker = thread_scoped_lock(*entry.mutex);
144 /* If the thing isn't cached */
145 if(entry.program == NULL) {
146 /* return with the caller's lock holder holding the slot lock */
150 /* the item was already cached, release the slot lock */
151 slot_locker.unlock();
153 cl_int ciErr = clRetainProgram(entry.program);
154 assert(ciErr == CL_SUCCESS);
157 return entry.program;
160 void OpenCLCache::store_context(cl_platform_id platform,
163 thread_scoped_lock& slot_locker)
165 assert(platform != NULL);
166 assert(device != NULL);
167 assert(context != NULL);
169 OpenCLCache &self = global_instance();
171 thread_scoped_lock cache_lock(self.cache_lock);
172 CacheMap::iterator i = self.cache.find(PlatformDevicePair(platform, device));
175 Slot &slot = i->second;
178 assert(i != self.cache.end());
179 assert(slot.context == NULL);
181 slot.context = context;
183 /* unlock the slot */
184 slot_locker.unlock();
186 /* increment reference count in OpenCL.
187 * The caller is going to release the object when done with it. */
188 cl_int ciErr = clRetainContext(context);
189 assert(ciErr == CL_SUCCESS);
193 void OpenCLCache::store_program(cl_platform_id platform,
197 thread_scoped_lock& slot_locker)
199 assert(platform != NULL);
200 assert(device != NULL);
201 assert(program != NULL);
203 OpenCLCache &self = global_instance();
205 thread_scoped_lock cache_lock(self.cache_lock);
207 CacheMap::iterator i = self.cache.find(PlatformDevicePair(platform, device));
208 assert(i != self.cache.end());
209 Slot &slot = i->second;
211 Slot::EntryMap::iterator i2 = slot.programs.find(key);
212 assert(i2 != slot.programs.end());
213 Slot::ProgramEntry &entry = i2->second;
215 assert(entry.program == NULL);
219 entry.program = program;
221 /* unlock the slot */
222 slot_locker.unlock();
224 /* Increment reference count in OpenCL.
225 * The caller is going to release the object when done with it.
227 cl_int ciErr = clRetainProgram(program);
228 assert(ciErr == CL_SUCCESS);
232 string OpenCLCache::get_kernel_md5()
234 OpenCLCache &self = global_instance();
235 thread_scoped_lock lock(self.kernel_md5_lock);
237 if(self.kernel_md5.empty()) {
238 self.kernel_md5 = path_files_md5_hash(path_get("source"));
240 return self.kernel_md5;
243 OpenCLDeviceBase::OpenCLProgram::OpenCLProgram(OpenCLDeviceBase *device,
246 string kernel_build_options,
249 program_name(program_name),
250 kernel_file(kernel_file),
251 kernel_build_options(kernel_build_options),
252 use_stdout(use_stdout)
258 OpenCLDeviceBase::OpenCLProgram::~OpenCLProgram()
263 void OpenCLDeviceBase::OpenCLProgram::release()
265 for(map<ustring, cl_kernel>::iterator kernel = kernels.begin(); kernel != kernels.end(); ++kernel) {
267 clReleaseKernel(kernel->second);
268 kernel->second = NULL;
272 clReleaseProgram(program);
277 void OpenCLDeviceBase::OpenCLProgram::add_log(string msg, bool debug)
283 printf("%s\n", msg.c_str());
291 void OpenCLDeviceBase::OpenCLProgram::add_error(string msg)
294 fprintf(stderr, "%s\n", msg.c_str());
296 if(error_msg == "") {
302 void OpenCLDeviceBase::OpenCLProgram::add_kernel(ustring name)
304 if(!kernels.count(name)) {
305 kernels[name] = NULL;
309 bool OpenCLDeviceBase::OpenCLProgram::build_kernel(const string *debug_src)
311 string build_options;
312 build_options = device->kernel_build_options(debug_src) + kernel_build_options;
314 VLOG(1) << "Build options passed to clBuildProgram: '"
315 << build_options << "'.";
316 cl_int ciErr = clBuildProgram(program, 0, NULL, build_options.c_str(), NULL, NULL);
318 /* show warnings even if build is successful */
319 size_t ret_val_size = 0;
321 clGetProgramBuildInfo(program, device->cdDevice, CL_PROGRAM_BUILD_LOG, 0, NULL, &ret_val_size);
323 if(ciErr != CL_SUCCESS) {
324 add_error(string("OpenCL build failed with error ") + clewErrorString(ciErr) + ", errors in console.");
327 if(ret_val_size > 1) {
328 vector<char> build_log(ret_val_size + 1);
329 clGetProgramBuildInfo(program, device->cdDevice, CL_PROGRAM_BUILD_LOG, ret_val_size, &build_log[0], NULL);
331 build_log[ret_val_size] = '\0';
332 /* Skip meaningless empty output from the NVidia compiler. */
333 if(!(ret_val_size == 2 && build_log[0] == '\n')) {
334 add_log(string("OpenCL program ") + program_name + " build output: " + string(&build_log[0]), ciErr == CL_SUCCESS);
338 return (ciErr == CL_SUCCESS);
341 bool OpenCLDeviceBase::OpenCLProgram::compile_kernel(const string *debug_src)
343 string source = "#include \"kernel/kernels/opencl/" + kernel_file + "\"\n";
344 /* We compile kernels consisting of many files. unfortunately OpenCL
345 * kernel caches do not seem to recognize changes in included files.
346 * so we force recompile on changes by adding the md5 hash of all files.
348 source = path_source_replace_includes(source, path_get("source"));
349 source += "\n// " + util_md5_string(source) + "\n";
352 path_write_text(*debug_src, source);
355 size_t source_len = source.size();
356 const char *source_str = source.c_str();
359 program = clCreateProgramWithSource(device->cxContext,
365 if(ciErr != CL_SUCCESS) {
366 add_error(string("OpenCL program creation failed: ") + clewErrorString(ciErr));
370 double starttime = time_dt();
371 add_log(string("Compiling OpenCL program ") + program_name.c_str(), false);
372 add_log(string("Build flags: ") + kernel_build_options, true);
374 if(!build_kernel(debug_src))
377 add_log(string("Kernel compilation of ") + program_name + " finished in " + string_printf("%.2lfs.\n", time_dt() - starttime), false);
382 bool OpenCLDeviceBase::OpenCLProgram::load_binary(const string& clbin,
383 const string *debug_src)
385 /* read binary into memory */
386 vector<uint8_t> binary;
388 if(!path_read_binary(clbin, binary)) {
389 add_error(string_printf("OpenCL failed to read cached binary %s.", clbin.c_str()));
394 cl_int status, ciErr;
395 size_t size = binary.size();
396 const uint8_t *bytes = &binary[0];
398 program = clCreateProgramWithBinary(device->cxContext, 1, &device->cdDevice,
399 &size, &bytes, &status, &ciErr);
401 if(status != CL_SUCCESS || ciErr != CL_SUCCESS) {
402 add_error(string("OpenCL failed create program from cached binary ") + clbin + ": "
403 + clewErrorString(status) + " " + clewErrorString(ciErr));
407 if(!build_kernel(debug_src))
413 bool OpenCLDeviceBase::OpenCLProgram::save_binary(const string& clbin)
416 clGetProgramInfo(program, CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &size, NULL);
421 vector<uint8_t> binary(size);
422 uint8_t *bytes = &binary[0];
424 clGetProgramInfo(program, CL_PROGRAM_BINARIES, sizeof(uint8_t*), &bytes, NULL);
426 return path_write_binary(clbin, binary);
429 void OpenCLDeviceBase::OpenCLProgram::load()
435 string device_md5 = device->device_md5_hash(kernel_build_options);
437 /* Try to use cached kernel. */
438 thread_scoped_lock cache_locker;
439 ustring cache_key(program_name + device_md5);
440 program = device->load_cached_kernel(cache_key,
444 add_log(string("OpenCL program ") + program_name + " not found in cache.", true);
446 /* need to create source to get md5 */
447 string source = "#include \"kernel/kernels/opencl/" + kernel_file + "\"\n";
448 source = path_source_replace_includes(source, path_get("source"));
450 string basename = "cycles_kernel_" + program_name + "_" + device_md5 + "_" + util_md5_string(source);
451 basename = path_cache_get(path_join("kernels", basename));
452 string clbin = basename + ".clbin";
454 /* path to preprocessed source for debugging */
455 string clsrc, *debug_src = NULL;
457 if(OpenCLInfo::use_debug()) {
458 clsrc = basename + ".cl";
462 /* If binary kernel exists already, try use it. */
463 if(path_exists(clbin) && load_binary(clbin)) {
464 /* Kernel loaded from binary, nothing to do. */
465 add_log(string("Loaded program from ") + clbin + ".", true);
468 add_log(string("Kernel file ") + clbin + " either doesn't exist or failed to be loaded by driver.", true);
470 /* If does not exist or loading binary failed, compile kernel. */
471 if(!compile_kernel(debug_src)) {
475 /* Save binary for reuse. */
476 if(!save_binary(clbin)) {
477 add_log(string("Saving compiled OpenCL kernel to ") + clbin + " failed!", true);
481 /* Cache the program. */
482 device->store_cached_kernel(program,
487 add_log(string("Found cached OpenCL program ") + program_name + ".", true);
490 for(map<ustring, cl_kernel>::iterator kernel = kernels.begin(); kernel != kernels.end(); ++kernel) {
491 assert(kernel->second == NULL);
493 string name = "kernel_ocl_" + kernel->first.string();
494 kernel->second = clCreateKernel(program, name.c_str(), &ciErr);
495 if(device->opencl_error(ciErr)) {
496 add_error(string("Error getting kernel ") + name + " from program " + program_name + ": " + clewErrorString(ciErr));
504 void OpenCLDeviceBase::OpenCLProgram::report_error()
506 /* If loaded is true, there was no error. */
508 /* if use_stdout is true, the error was already reported. */
509 if(use_stdout) return;
511 cerr << error_msg << endl;
512 if(!compile_output.empty()) {
513 cerr << "OpenCL kernel build output for " << program_name << ":" << endl;
514 cerr << compile_output << endl;
518 cl_kernel OpenCLDeviceBase::OpenCLProgram::operator()()
520 assert(kernels.size() == 1);
521 return kernels.begin()->second;
524 cl_kernel OpenCLDeviceBase::OpenCLProgram::operator()(ustring name)
526 assert(kernels.count(name));
527 return kernels[name];
530 cl_device_type OpenCLInfo::device_type()
532 switch(DebugFlags().opencl.device_type)
534 case DebugFlags::OpenCL::DEVICE_NONE:
536 case DebugFlags::OpenCL::DEVICE_ALL:
537 return CL_DEVICE_TYPE_ALL;
538 case DebugFlags::OpenCL::DEVICE_DEFAULT:
539 return CL_DEVICE_TYPE_DEFAULT;
540 case DebugFlags::OpenCL::DEVICE_CPU:
541 return CL_DEVICE_TYPE_CPU;
542 case DebugFlags::OpenCL::DEVICE_GPU:
543 return CL_DEVICE_TYPE_GPU;
544 case DebugFlags::OpenCL::DEVICE_ACCELERATOR:
545 return CL_DEVICE_TYPE_ACCELERATOR;
547 return CL_DEVICE_TYPE_ALL;
551 bool OpenCLInfo::use_debug()
553 return DebugFlags().opencl.debug;
556 bool OpenCLInfo::use_single_program()
558 return DebugFlags().opencl.single_program;
561 bool OpenCLInfo::kernel_use_advanced_shading(const string& platform)
563 /* keep this in sync with kernel_types.h! */
564 if(platform == "NVIDIA CUDA")
566 else if(platform == "Apple")
568 else if(platform == "AMD Accelerated Parallel Processing")
570 else if(platform == "Intel(R) OpenCL")
572 /* Make sure officially unsupported OpenCL platforms
573 * does not set up to use advanced shading.
578 bool OpenCLInfo::kernel_use_split(const string& platform_name,
579 const cl_device_type device_type)
581 if(DebugFlags().opencl.kernel_type == DebugFlags::OpenCL::KERNEL_SPLIT) {
582 VLOG(1) << "Forcing split kernel to use.";
585 if(DebugFlags().opencl.kernel_type == DebugFlags::OpenCL::KERNEL_MEGA) {
586 VLOG(1) << "Forcing mega kernel to use.";
589 /* TODO(sergey): Replace string lookups with more enum-like API,
590 * similar to device/vendor checks blender's gpu.
592 if(platform_name == "AMD Accelerated Parallel Processing" &&
593 device_type == CL_DEVICE_TYPE_GPU)
600 bool OpenCLInfo::device_supported(const string& platform_name,
601 const cl_device_id device_id)
603 cl_device_type device_type;
604 if(!get_device_type(device_id, &device_type)) {
608 if(!get_device_name(device_id, &device_name)) {
611 /* It is possible tyo have Iris GPU on AMD/Apple OpenCL framework
612 * (aka, it will not be on Intel framework). This isn't supported
613 * and needs an explicit blacklist.
615 if(strstr(device_name.c_str(), "Iris")) {
618 if(platform_name == "AMD Accelerated Parallel Processing" &&
619 device_type == CL_DEVICE_TYPE_GPU)
623 if(platform_name == "Apple" && device_type == CL_DEVICE_TYPE_GPU) {
629 bool OpenCLInfo::platform_version_check(cl_platform_id platform,
632 const int req_major = 1, req_minor = 1;
635 clGetPlatformInfo(platform,
640 if(sscanf(version, "OpenCL %d.%d", &major, &minor) < 2) {
642 *error = string_printf("OpenCL: failed to parse platform version string (%s).", version);
646 if(!((major == req_major && minor >= req_minor) || (major > req_major))) {
648 *error = string_printf("OpenCL: platform version 1.1 or later required, found %d.%d", major, minor);
658 bool OpenCLInfo::device_version_check(cl_device_id device,
661 const int req_major = 1, req_minor = 1;
664 clGetDeviceInfo(device,
665 CL_DEVICE_OPENCL_C_VERSION,
669 if(sscanf(version, "OpenCL C %d.%d", &major, &minor) < 2) {
671 *error = string_printf("OpenCL: failed to parse OpenCL C version string (%s).", version);
675 if(!((major == req_major && minor >= req_minor) || (major > req_major))) {
677 *error = string_printf("OpenCL: C version 1.1 or later required, found %d.%d", major, minor);
687 string OpenCLInfo::get_hardware_id(string platform_name, cl_device_id device_id)
689 if(platform_name == "AMD Accelerated Parallel Processing" || platform_name == "Apple") {
690 /* Use cl_amd_device_topology extension. */
691 cl_char topology[24];
692 if(clGetDeviceInfo(device_id, 0x4037, sizeof(topology), topology, NULL) == CL_SUCCESS && topology[0] == 1) {
693 return string_printf("%02x:%02x.%01x",
694 (unsigned int)topology[21],
695 (unsigned int)topology[22],
696 (unsigned int)topology[23]);
699 else if(platform_name == "NVIDIA CUDA") {
700 /* Use two undocumented options of the cl_nv_device_attribute_query extension. */
701 cl_int bus_id, slot_id;
702 if(clGetDeviceInfo(device_id, 0x4008, sizeof(cl_int), &bus_id, NULL) == CL_SUCCESS &&
703 clGetDeviceInfo(device_id, 0x4009, sizeof(cl_int), &slot_id, NULL) == CL_SUCCESS) {
704 return string_printf("%02x:%02x.%01x",
705 (unsigned int)(bus_id),
706 (unsigned int)(slot_id >> 3),
707 (unsigned int)(slot_id & 0x7));
710 /* No general way to get a hardware ID from OpenCL => give up. */
714 void OpenCLInfo::get_usable_devices(vector<OpenCLPlatformDevice> *usable_devices,
717 const bool force_all_platforms = force_all ||
718 (DebugFlags().opencl.kernel_type != DebugFlags::OpenCL::KERNEL_DEFAULT);
719 const cl_device_type device_type = OpenCLInfo::device_type();
720 static bool first_time = true;
721 #define FIRST_VLOG(severity) if(first_time) VLOG(severity)
723 usable_devices->clear();
725 if(device_type == 0) {
726 FIRST_VLOG(2) << "OpenCL devices are forced to be disabled.";
732 vector<cl_device_id> device_ids;
733 vector<cl_platform_id> platform_ids;
736 if(!get_platforms(&platform_ids, &error)) {
737 FIRST_VLOG(2) << "Error fetching platforms:"
738 << string(clewErrorString(error));
742 if(platform_ids.size() == 0) {
743 FIRST_VLOG(2) << "No OpenCL platforms were found.";
747 /* Devices are numbered consecutively across platforms. */
748 for(int platform = 0; platform < platform_ids.size(); platform++) {
749 cl_platform_id platform_id = platform_ids[platform];
750 string platform_name;
751 if(!get_platform_name(platform_id, &platform_name)) {
752 FIRST_VLOG(2) << "Failed to get platform name, ignoring.";
755 FIRST_VLOG(2) << "Enumerating devices for platform "
756 << platform_name << ".";
757 if(!platform_version_check(platform_id)) {
758 FIRST_VLOG(2) << "Ignoring platform " << platform_name
759 << " due to too old compiler version.";
762 if(!get_platform_devices(platform_id,
767 FIRST_VLOG(2) << "Ignoring platform " << platform_name
768 << ", failed to fetch of devices: "
769 << string(clewErrorString(error));
772 if(device_ids.size() == 0) {
773 FIRST_VLOG(2) << "Ignoring platform " << platform_name
774 << ", it has no devices.";
777 for(int num = 0; num < device_ids.size(); num++) {
778 const cl_device_id device_id = device_ids[num];
780 if(!get_device_name(device_id, &device_name, &error)) {
781 FIRST_VLOG(2) << "Failed to fetch device name: "
782 << string(clewErrorString(error))
786 if(!device_version_check(device_id)) {
787 FIRST_VLOG(2) << "Ignoring device " << device_name
788 << " due to old compiler version.";
791 if(force_all_platforms ||
792 device_supported(platform_name, device_id))
794 cl_device_type device_type;
795 if(!get_device_type(device_id, &device_type, &error)) {
796 FIRST_VLOG(2) << "Ignoring device " << device_name
797 << ", failed to fetch device type:"
798 << string(clewErrorString(error));
801 string readable_device_name =
802 get_readable_device_name(device_id);
803 if(readable_device_name != device_name) {
804 FIRST_VLOG(2) << "Using more readable device name: "
805 << readable_device_name;
807 FIRST_VLOG(2) << "Adding new device "
808 << readable_device_name << ".";
809 string hardware_id = get_hardware_id(platform_name, device_id);
810 usable_devices->push_back(OpenCLPlatformDevice(
815 readable_device_name,
819 FIRST_VLOG(2) << "Ignoring device " << device_name
820 << ", not officially supported yet.";
827 bool OpenCLInfo::get_platforms(vector<cl_platform_id> *platform_ids,
830 /* Reset from possible previous state. */
831 platform_ids->resize(0);
832 cl_uint num_platforms;
833 if(!get_num_platforms(&num_platforms, error)) {
836 /* Get actual platforms. */
838 platform_ids->resize(num_platforms);
839 if((err = clGetPlatformIDs(num_platforms,
840 &platform_ids->at(0),
841 NULL)) != CL_SUCCESS) {
853 vector<cl_platform_id> OpenCLInfo::get_platforms()
855 vector<cl_platform_id> platform_ids;
856 get_platforms(&platform_ids);
860 bool OpenCLInfo::get_num_platforms(cl_uint *num_platforms, cl_int *error)
863 if((err = clGetPlatformIDs(0, NULL, num_platforms)) != CL_SUCCESS) {
876 cl_uint OpenCLInfo::get_num_platforms()
878 cl_uint num_platforms;
879 if(!get_num_platforms(&num_platforms)) {
882 return num_platforms;
885 bool OpenCLInfo::get_platform_name(cl_platform_id platform_id,
886 string *platform_name)
889 if(clGetPlatformInfo(platform_id,
898 *platform_name = buffer;
902 string OpenCLInfo::get_platform_name(cl_platform_id platform_id)
904 string platform_name;
905 if (!get_platform_name(platform_id, &platform_name)) {
908 return platform_name;
911 bool OpenCLInfo::get_num_platform_devices(cl_platform_id platform_id,
912 cl_device_type device_type,
913 cl_uint *num_devices,
917 if((err = clGetDeviceIDs(platform_id,
921 num_devices)) != CL_SUCCESS)
935 cl_uint OpenCLInfo::get_num_platform_devices(cl_platform_id platform_id,
936 cl_device_type device_type)
939 if(!get_num_platform_devices(platform_id,
948 bool OpenCLInfo::get_platform_devices(cl_platform_id platform_id,
949 cl_device_type device_type,
950 vector<cl_device_id> *device_ids,
953 /* Reset from possible previous state. */
954 device_ids->resize(0);
955 /* Get number of devices to pre-allocate memory. */
957 if(!get_num_platform_devices(platform_id,
964 /* Get actual device list. */
965 device_ids->resize(num_devices);
967 if((err = clGetDeviceIDs(platform_id,
971 NULL)) != CL_SUCCESS)
984 vector<cl_device_id> OpenCLInfo::get_platform_devices(cl_platform_id platform_id,
985 cl_device_type device_type)
987 vector<cl_device_id> devices;
988 get_platform_devices(platform_id, device_type, &devices);
992 bool OpenCLInfo::get_device_name(cl_device_id device_id,
998 if((err = clGetDeviceInfo(device_id,
1002 NULL)) != CL_SUCCESS)
1011 *error = CL_SUCCESS;
1013 *device_name = buffer;
1017 string OpenCLInfo::get_device_name(cl_device_id device_id)
1020 if(!get_device_name(device_id, &device_name)) {
1026 bool OpenCLInfo::get_device_type(cl_device_id device_id,
1027 cl_device_type *device_type,
1031 if((err = clGetDeviceInfo(device_id,
1033 sizeof(cl_device_type),
1035 NULL)) != CL_SUCCESS)
1044 *error = CL_SUCCESS;
1049 cl_device_type OpenCLInfo::get_device_type(cl_device_id device_id)
1051 cl_device_type device_type;
1052 if(!get_device_type(device_id, &device_type)) {
1058 string OpenCLInfo::get_readable_device_name(cl_device_id device_id)
1060 char board_name[1024];
1062 if(clGetDeviceInfo(device_id,
1063 CL_DEVICE_BOARD_NAME_AMD,
1066 &length) == CL_SUCCESS)
1068 if(length != 0 && board_name[0] != '\0') {
1072 /* Fallback to standard device name API. */
1073 return get_device_name(device_id);