diff options
Diffstat (limited to 'intern/cycles/device/opencl/opencl_util.cpp')
-rw-r--r-- | intern/cycles/device/opencl/opencl_util.cpp | 1948 |
1 files changed, 931 insertions, 1017 deletions
diff --git a/intern/cycles/device/opencl/opencl_util.cpp b/intern/cycles/device/opencl/opencl_util.cpp index 5a1e12af8ab..cc40ad42b06 100644 --- a/intern/cycles/device/opencl/opencl_util.cpp +++ b/intern/cycles/device/opencl/opencl_util.cpp @@ -16,1059 +16,1017 @@ #ifdef WITH_OPENCL -#include "device/opencl/opencl.h" -#include "device/device_intern.h" +# include "device/opencl/opencl.h" +# include "device/device_intern.h" -#include "util/util_debug.h" -#include "util/util_logging.h" -#include "util/util_md5.h" -#include "util/util_path.h" -#include "util/util_time.h" -#include "util/util_system.h" +# include "util/util_debug.h" +# include "util/util_logging.h" +# include "util/util_md5.h" +# include "util/util_path.h" +# include "util/util_time.h" +# include "util/util_system.h" using std::cerr; using std::endl; CCL_NAMESPACE_BEGIN -OpenCLCache::Slot::ProgramEntry::ProgramEntry() - : program(NULL), - mutex(NULL) +OpenCLCache::Slot::ProgramEntry::ProgramEntry() : program(NULL), mutex(NULL) { } -OpenCLCache::Slot::ProgramEntry::ProgramEntry(const ProgramEntry& rhs) - : program(rhs.program), - mutex(NULL) +OpenCLCache::Slot::ProgramEntry::ProgramEntry(const ProgramEntry &rhs) + : program(rhs.program), mutex(NULL) { } OpenCLCache::Slot::ProgramEntry::~ProgramEntry() { - delete mutex; + delete mutex; } -OpenCLCache::Slot::Slot() - : context_mutex(NULL), - context(NULL) +OpenCLCache::Slot::Slot() : context_mutex(NULL), context(NULL) { } -OpenCLCache::Slot::Slot(const Slot& rhs) - : context_mutex(NULL), - context(NULL), - programs(rhs.programs) +OpenCLCache::Slot::Slot(const Slot &rhs) + : context_mutex(NULL), context(NULL), programs(rhs.programs) { } OpenCLCache::Slot::~Slot() { - delete context_mutex; + delete context_mutex; } -OpenCLCache& OpenCLCache::global_instance() +OpenCLCache &OpenCLCache::global_instance() { - static OpenCLCache instance; - return instance; + static OpenCLCache instance; + return instance; } cl_context OpenCLCache::get_context(cl_platform_id platform, cl_device_id device, - thread_scoped_lock& slot_locker) + thread_scoped_lock &slot_locker) { - assert(platform != NULL); + assert(platform != NULL); - OpenCLCache& self = global_instance(); + OpenCLCache &self = global_instance(); - thread_scoped_lock cache_lock(self.cache_lock); + thread_scoped_lock cache_lock(self.cache_lock); - pair<CacheMap::iterator,bool> ins = self.cache.insert( - CacheMap::value_type(PlatformDevicePair(platform, device), Slot())); + pair<CacheMap::iterator, bool> ins = self.cache.insert( + CacheMap::value_type(PlatformDevicePair(platform, device), Slot())); - Slot &slot = ins.first->second; + Slot &slot = ins.first->second; - /* create slot lock only while holding cache lock */ - if(!slot.context_mutex) - slot.context_mutex = new thread_mutex; + /* create slot lock only while holding cache lock */ + if (!slot.context_mutex) + slot.context_mutex = new thread_mutex; - /* need to unlock cache before locking slot, to allow store to complete */ - cache_lock.unlock(); + /* need to unlock cache before locking slot, to allow store to complete */ + cache_lock.unlock(); - /* lock the slot */ - slot_locker = thread_scoped_lock(*slot.context_mutex); + /* lock the slot */ + slot_locker = thread_scoped_lock(*slot.context_mutex); - /* If the thing isn't cached */ - if(slot.context == NULL) { - /* return with the caller's lock holder holding the slot lock */ - return NULL; - } + /* If the thing isn't cached */ + if (slot.context == NULL) { + /* return with the caller's lock holder holding the slot lock */ + return NULL; + } - /* the item was already cached, release the slot lock */ - slot_locker.unlock(); + /* the item was already cached, release the slot lock */ + slot_locker.unlock(); - cl_int ciErr = clRetainContext(slot.context); - assert(ciErr == CL_SUCCESS); - (void) ciErr; + cl_int ciErr = clRetainContext(slot.context); + assert(ciErr == CL_SUCCESS); + (void)ciErr; - return slot.context; + return slot.context; } cl_program OpenCLCache::get_program(cl_platform_id platform, cl_device_id device, ustring key, - thread_scoped_lock& slot_locker) + thread_scoped_lock &slot_locker) { - assert(platform != NULL); + assert(platform != NULL); - OpenCLCache& self = global_instance(); + OpenCLCache &self = global_instance(); - thread_scoped_lock cache_lock(self.cache_lock); + thread_scoped_lock cache_lock(self.cache_lock); - pair<CacheMap::iterator,bool> ins = self.cache.insert( - CacheMap::value_type(PlatformDevicePair(platform, device), Slot())); + pair<CacheMap::iterator, bool> ins = self.cache.insert( + CacheMap::value_type(PlatformDevicePair(platform, device), Slot())); - Slot &slot = ins.first->second; + Slot &slot = ins.first->second; - pair<Slot::EntryMap::iterator,bool> ins2 = slot.programs.insert( - Slot::EntryMap::value_type(key, Slot::ProgramEntry())); + pair<Slot::EntryMap::iterator, bool> ins2 = slot.programs.insert( + Slot::EntryMap::value_type(key, Slot::ProgramEntry())); - Slot::ProgramEntry &entry = ins2.first->second; + Slot::ProgramEntry &entry = ins2.first->second; - /* create slot lock only while holding cache lock */ - if(!entry.mutex) - entry.mutex = new thread_mutex; + /* create slot lock only while holding cache lock */ + if (!entry.mutex) + entry.mutex = new thread_mutex; - /* need to unlock cache before locking slot, to allow store to complete */ - cache_lock.unlock(); + /* need to unlock cache before locking slot, to allow store to complete */ + cache_lock.unlock(); - /* lock the slot */ - slot_locker = thread_scoped_lock(*entry.mutex); + /* lock the slot */ + slot_locker = thread_scoped_lock(*entry.mutex); - /* If the thing isn't cached */ - if(entry.program == NULL) { - /* return with the caller's lock holder holding the slot lock */ - return NULL; - } + /* If the thing isn't cached */ + if (entry.program == NULL) { + /* return with the caller's lock holder holding the slot lock */ + return NULL; + } - /* the item was already cached, release the slot lock */ - slot_locker.unlock(); + /* the item was already cached, release the slot lock */ + slot_locker.unlock(); - cl_int ciErr = clRetainProgram(entry.program); - assert(ciErr == CL_SUCCESS); - (void) ciErr; + cl_int ciErr = clRetainProgram(entry.program); + assert(ciErr == CL_SUCCESS); + (void)ciErr; - return entry.program; + return entry.program; } void OpenCLCache::store_context(cl_platform_id platform, cl_device_id device, cl_context context, - thread_scoped_lock& slot_locker) + thread_scoped_lock &slot_locker) { - assert(platform != NULL); - assert(device != NULL); - assert(context != NULL); + assert(platform != NULL); + assert(device != NULL); + assert(context != NULL); - OpenCLCache &self = global_instance(); + OpenCLCache &self = global_instance(); - thread_scoped_lock cache_lock(self.cache_lock); - CacheMap::iterator i = self.cache.find(PlatformDevicePair(platform, device)); - cache_lock.unlock(); + thread_scoped_lock cache_lock(self.cache_lock); + CacheMap::iterator i = self.cache.find(PlatformDevicePair(platform, device)); + cache_lock.unlock(); - Slot &slot = i->second; + Slot &slot = i->second; - /* sanity check */ - assert(i != self.cache.end()); - assert(slot.context == NULL); + /* sanity check */ + assert(i != self.cache.end()); + assert(slot.context == NULL); - slot.context = context; + slot.context = context; - /* unlock the slot */ - slot_locker.unlock(); + /* unlock the slot */ + slot_locker.unlock(); - /* increment reference count in OpenCL. - * The caller is going to release the object when done with it. */ - cl_int ciErr = clRetainContext(context); - assert(ciErr == CL_SUCCESS); - (void) ciErr; + /* increment reference count in OpenCL. + * The caller is going to release the object when done with it. */ + cl_int ciErr = clRetainContext(context); + assert(ciErr == CL_SUCCESS); + (void)ciErr; } void OpenCLCache::store_program(cl_platform_id platform, cl_device_id device, cl_program program, ustring key, - thread_scoped_lock& slot_locker) + thread_scoped_lock &slot_locker) { - assert(platform != NULL); - assert(device != NULL); - assert(program != NULL); + assert(platform != NULL); + assert(device != NULL); + assert(program != NULL); - OpenCLCache &self = global_instance(); + OpenCLCache &self = global_instance(); - thread_scoped_lock cache_lock(self.cache_lock); + thread_scoped_lock cache_lock(self.cache_lock); - CacheMap::iterator i = self.cache.find(PlatformDevicePair(platform, device)); - assert(i != self.cache.end()); - Slot &slot = i->second; + CacheMap::iterator i = self.cache.find(PlatformDevicePair(platform, device)); + assert(i != self.cache.end()); + Slot &slot = i->second; - Slot::EntryMap::iterator i2 = slot.programs.find(key); - assert(i2 != slot.programs.end()); - Slot::ProgramEntry &entry = i2->second; + Slot::EntryMap::iterator i2 = slot.programs.find(key); + assert(i2 != slot.programs.end()); + Slot::ProgramEntry &entry = i2->second; - assert(entry.program == NULL); + assert(entry.program == NULL); - cache_lock.unlock(); + cache_lock.unlock(); - entry.program = program; + entry.program = program; - /* unlock the slot */ - slot_locker.unlock(); + /* unlock the slot */ + slot_locker.unlock(); - /* Increment reference count in OpenCL. - * The caller is going to release the object when done with it. - */ - cl_int ciErr = clRetainProgram(program); - assert(ciErr == CL_SUCCESS); - (void) ciErr; + /* Increment reference count in OpenCL. + * The caller is going to release the object when done with it. + */ + cl_int ciErr = clRetainProgram(program); + assert(ciErr == CL_SUCCESS); + (void)ciErr; } string OpenCLCache::get_kernel_md5() { - OpenCLCache &self = global_instance(); - thread_scoped_lock lock(self.kernel_md5_lock); + OpenCLCache &self = global_instance(); + thread_scoped_lock lock(self.kernel_md5_lock); - if(self.kernel_md5.empty()) { - self.kernel_md5 = path_files_md5_hash(path_get("source")); - } - return self.kernel_md5; + if (self.kernel_md5.empty()) { + self.kernel_md5 = path_files_md5_hash(path_get("source")); + } + return self.kernel_md5; } -static string get_program_source(const string& kernel_file) +static string get_program_source(const string &kernel_file) { - string source = "#include \"kernel/kernels/opencl/" + kernel_file + "\"\n"; - /* We compile kernels consisting of many files. unfortunately OpenCL - * kernel caches do not seem to recognize changes in included files. - * so we force recompile on changes by adding the md5 hash of all files. - */ - source = path_source_replace_includes(source, path_get("source")); - source += "\n// " + util_md5_string(source) + "\n"; - return source; + string source = "#include \"kernel/kernels/opencl/" + kernel_file + "\"\n"; + /* We compile kernels consisting of many files. unfortunately OpenCL + * kernel caches do not seem to recognize changes in included files. + * so we force recompile on changes by adding the md5 hash of all files. + */ + source = path_source_replace_includes(source, path_get("source")); + source += "\n// " + util_md5_string(source) + "\n"; + return source; } OpenCLDevice::OpenCLProgram::OpenCLProgram(OpenCLDevice *device, - const string& program_name, - const string& kernel_file, - const string& kernel_build_options, - bool use_stdout) - : device(device), - program_name(program_name), - kernel_file(kernel_file), - kernel_build_options(kernel_build_options), - use_stdout(use_stdout) + const string &program_name, + const string &kernel_file, + const string &kernel_build_options, + bool use_stdout) + : device(device), + program_name(program_name), + kernel_file(kernel_file), + kernel_build_options(kernel_build_options), + use_stdout(use_stdout) { - loaded = false; - needs_compiling = true; - program = NULL; + loaded = false; + needs_compiling = true; + program = NULL; } OpenCLDevice::OpenCLProgram::~OpenCLProgram() { - release(); + release(); } void OpenCLDevice::OpenCLProgram::release() { - for(map<ustring, cl_kernel>::iterator kernel = kernels.begin(); kernel != kernels.end(); ++kernel) { - if(kernel->second) { - clReleaseKernel(kernel->second); - kernel->second = NULL; - } - } - if(program) { - clReleaseProgram(program); - program = NULL; - } + for (map<ustring, cl_kernel>::iterator kernel = kernels.begin(); kernel != kernels.end(); + ++kernel) { + if (kernel->second) { + clReleaseKernel(kernel->second); + kernel->second = NULL; + } + } + if (program) { + clReleaseProgram(program); + program = NULL; + } } -void OpenCLDevice::OpenCLProgram::add_log(const string& msg, bool debug) +void OpenCLDevice::OpenCLProgram::add_log(const string &msg, bool debug) { - if(!use_stdout) { - log += msg + "\n"; - } - else if(!debug) { - printf("%s\n", msg.c_str()); - fflush(stdout); - } - else { - VLOG(2) << msg; - } + if (!use_stdout) { + log += msg + "\n"; + } + else if (!debug) { + printf("%s\n", msg.c_str()); + fflush(stdout); + } + else { + VLOG(2) << msg; + } } -void OpenCLDevice::OpenCLProgram::add_error(const string& msg) +void OpenCLDevice::OpenCLProgram::add_error(const string &msg) { - if(use_stdout) { - fprintf(stderr, "%s\n", msg.c_str()); - } - if(error_msg == "") { - error_msg += "\n"; - } - error_msg += msg; + if (use_stdout) { + fprintf(stderr, "%s\n", msg.c_str()); + } + if (error_msg == "") { + error_msg += "\n"; + } + error_msg += msg; } void OpenCLDevice::OpenCLProgram::add_kernel(ustring name) { - if(!kernels.count(name)) { - kernels[name] = NULL; - } + if (!kernels.count(name)) { + kernels[name] = NULL; + } } bool OpenCLDevice::OpenCLProgram::build_kernel(const string *debug_src) { - string build_options; - build_options = device->kernel_build_options(debug_src) + kernel_build_options; + string build_options; + build_options = device->kernel_build_options(debug_src) + kernel_build_options; - VLOG(1) << "Build options passed to clBuildProgram: '" - << build_options << "'."; - cl_int ciErr = clBuildProgram(program, 0, NULL, build_options.c_str(), NULL, NULL); + VLOG(1) << "Build options passed to clBuildProgram: '" << build_options << "'."; + cl_int ciErr = clBuildProgram(program, 0, NULL, build_options.c_str(), NULL, NULL); - /* show warnings even if build is successful */ - size_t ret_val_size = 0; + /* show warnings even if build is successful */ + size_t ret_val_size = 0; - clGetProgramBuildInfo(program, device->cdDevice, CL_PROGRAM_BUILD_LOG, 0, NULL, &ret_val_size); + clGetProgramBuildInfo(program, device->cdDevice, CL_PROGRAM_BUILD_LOG, 0, NULL, &ret_val_size); - if(ciErr != CL_SUCCESS) { - add_error(string("OpenCL build failed with error ") + clewErrorString(ciErr) + ", errors in console."); - } + if (ciErr != CL_SUCCESS) { + add_error(string("OpenCL build failed with error ") + clewErrorString(ciErr) + + ", errors in console."); + } - if(ret_val_size > 1) { - vector<char> build_log(ret_val_size + 1); - clGetProgramBuildInfo(program, device->cdDevice, CL_PROGRAM_BUILD_LOG, ret_val_size, &build_log[0], NULL); + if (ret_val_size > 1) { + vector<char> build_log(ret_val_size + 1); + clGetProgramBuildInfo( + program, device->cdDevice, CL_PROGRAM_BUILD_LOG, ret_val_size, &build_log[0], NULL); - build_log[ret_val_size] = '\0'; - /* Skip meaningless empty output from the NVidia compiler. */ - if(!(ret_val_size == 2 && build_log[0] == '\n')) { - add_log(string("OpenCL program ") + program_name + " build output: " + string(&build_log[0]), ciErr == CL_SUCCESS); - } - } + build_log[ret_val_size] = '\0'; + /* Skip meaningless empty output from the NVidia compiler. */ + if (!(ret_val_size == 2 && build_log[0] == '\n')) { + add_log(string("OpenCL program ") + program_name + " build output: " + string(&build_log[0]), + ciErr == CL_SUCCESS); + } + } - return (ciErr == CL_SUCCESS); + return (ciErr == CL_SUCCESS); } bool OpenCLDevice::OpenCLProgram::compile_kernel(const string *debug_src) { - string source = get_program_source(kernel_file); + string source = get_program_source(kernel_file); - if(debug_src) { - path_write_text(*debug_src, source); - } + if (debug_src) { + path_write_text(*debug_src, source); + } - size_t source_len = source.size(); - const char *source_str = source.c_str(); - cl_int ciErr; + size_t source_len = source.size(); + const char *source_str = source.c_str(); + cl_int ciErr; - program = clCreateProgramWithSource(device->cxContext, - 1, - &source_str, - &source_len, - &ciErr); + program = clCreateProgramWithSource(device->cxContext, 1, &source_str, &source_len, &ciErr); - if(ciErr != CL_SUCCESS) { - add_error(string("OpenCL program creation failed: ") + clewErrorString(ciErr)); - return false; - } + if (ciErr != CL_SUCCESS) { + add_error(string("OpenCL program creation failed: ") + clewErrorString(ciErr)); + return false; + } - double starttime = time_dt(); - add_log(string("Cycles: compiling OpenCL program ") + program_name + "...", false); - add_log(string("Build flags: ") + kernel_build_options, true); + double starttime = time_dt(); + add_log(string("Cycles: compiling OpenCL program ") + program_name + "...", false); + add_log(string("Build flags: ") + kernel_build_options, true); - if(!build_kernel(debug_src)) - return false; + if (!build_kernel(debug_src)) + return false; - double elapsed = time_dt() - starttime; - add_log(string_printf("Kernel compilation of %s finished in %.2lfs.", program_name.c_str(), elapsed), false); + double elapsed = time_dt() - starttime; + add_log( + string_printf("Kernel compilation of %s finished in %.2lfs.", program_name.c_str(), elapsed), + false); - return true; + return true; } -static void escape_python_string(string& str) +static void escape_python_string(string &str) { - /* Escape string to be passed as a Python raw string with '' quotes'. */ - string_replace(str, "'", "\'"); + /* Escape string to be passed as a Python raw string with '' quotes'. */ + string_replace(str, "'", "\'"); } -bool OpenCLDevice::OpenCLProgram::compile_separate(const string& clbin) +bool OpenCLDevice::OpenCLProgram::compile_separate(const string &clbin) { - vector<string> args; - args.push_back("--background"); - args.push_back("--factory-startup"); - args.push_back("--python-expr"); - - int device_platform_id = device->device_num; - string device_name = device->device_name; - string platform_name = device->platform_name; - string build_options = device->kernel_build_options(NULL) + kernel_build_options; - string kernel_file_escaped = kernel_file; - string clbin_escaped = clbin; - - escape_python_string(device_name); - escape_python_string(platform_name); - escape_python_string(build_options); - escape_python_string(kernel_file_escaped); - escape_python_string(clbin_escaped); - - args.push_back( - string_printf( - "import _cycles; _cycles.opencl_compile(r'%d', r'%s', r'%s', r'%s', r'%s', r'%s')", - device_platform_id, - device_name.c_str(), - platform_name.c_str(), - build_options.c_str(), - kernel_file_escaped.c_str(), - clbin_escaped.c_str())); - - double starttime = time_dt(); - add_log(string("Cycles: compiling OpenCL program ") + program_name + "...", false); - add_log(string("Build flags: ") + kernel_build_options, true); - if(!system_call_self(args) || !path_exists(clbin)) { - return false; - } - - double elapsed = time_dt() - starttime; - add_log(string_printf("Kernel compilation of %s finished in %.2lfs.", program_name.c_str(), elapsed), false); - - return load_binary(clbin); + vector<string> args; + args.push_back("--background"); + args.push_back("--factory-startup"); + args.push_back("--python-expr"); + + int device_platform_id = device->device_num; + string device_name = device->device_name; + string platform_name = device->platform_name; + string build_options = device->kernel_build_options(NULL) + kernel_build_options; + string kernel_file_escaped = kernel_file; + string clbin_escaped = clbin; + + escape_python_string(device_name); + escape_python_string(platform_name); + escape_python_string(build_options); + escape_python_string(kernel_file_escaped); + escape_python_string(clbin_escaped); + + args.push_back(string_printf( + "import _cycles; _cycles.opencl_compile(r'%d', r'%s', r'%s', r'%s', r'%s', r'%s')", + device_platform_id, + device_name.c_str(), + platform_name.c_str(), + build_options.c_str(), + kernel_file_escaped.c_str(), + clbin_escaped.c_str())); + + double starttime = time_dt(); + add_log(string("Cycles: compiling OpenCL program ") + program_name + "...", false); + add_log(string("Build flags: ") + kernel_build_options, true); + if (!system_call_self(args) || !path_exists(clbin)) { + return false; + } + + double elapsed = time_dt() - starttime; + add_log( + string_printf("Kernel compilation of %s finished in %.2lfs.", program_name.c_str(), elapsed), + false); + + return load_binary(clbin); } /* Compile opencl kernel. This method is called from the _cycles Python * module compile kernels. Parameters must match function above. */ -bool device_opencl_compile_kernel(const vector<string>& parameters) +bool device_opencl_compile_kernel(const vector<string> ¶meters) { - int device_platform_id = std::stoi(parameters[0]); - const string& device_name = parameters[1]; - const string& platform_name = parameters[2]; - const string& build_options = parameters[3]; - const string& kernel_file = parameters[4]; - const string& binary_path = parameters[5]; - - if(clewInit() != CLEW_SUCCESS) { - return false; - } - - vector<OpenCLPlatformDevice> usable_devices; - OpenCLInfo::get_usable_devices(&usable_devices); - if(device_platform_id >= usable_devices.size()) { - return false; - } - - OpenCLPlatformDevice& platform_device = usable_devices[device_platform_id]; - if(platform_device.platform_name != platform_name || - platform_device.device_name != device_name) - { - return false; - } - - cl_platform_id platform = platform_device.platform_id; - cl_device_id device = platform_device.device_id; - const cl_context_properties context_props[] = { - CL_CONTEXT_PLATFORM, (cl_context_properties) platform, - 0, 0 - }; - - cl_int err; - cl_context context = clCreateContext(context_props, 1, &device, NULL, NULL, &err); - if(err != CL_SUCCESS) { - return false; - } - - string source = get_program_source(kernel_file); - size_t source_len = source.size(); - const char *source_str = source.c_str(); - cl_program program = clCreateProgramWithSource(context, 1, &source_str, &source_len, &err); - bool result = false; - - if(err == CL_SUCCESS) { - err = clBuildProgram(program, 0, NULL, build_options.c_str(), NULL, NULL); - - if(err == CL_SUCCESS) { - size_t size = 0; - clGetProgramInfo(program, CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &size, NULL); - if(size > 0) { - vector<uint8_t> binary(size); - uint8_t *bytes = &binary[0]; - clGetProgramInfo(program, CL_PROGRAM_BINARIES, sizeof(uint8_t*), &bytes, NULL); - result = path_write_binary(binary_path, binary); - } - } - clReleaseProgram(program); - } - - clReleaseContext(context); - - return result; + int device_platform_id = std::stoi(parameters[0]); + const string &device_name = parameters[1]; + const string &platform_name = parameters[2]; + const string &build_options = parameters[3]; + const string &kernel_file = parameters[4]; + const string &binary_path = parameters[5]; + + if (clewInit() != CLEW_SUCCESS) { + return false; + } + + vector<OpenCLPlatformDevice> usable_devices; + OpenCLInfo::get_usable_devices(&usable_devices); + if (device_platform_id >= usable_devices.size()) { + return false; + } + + OpenCLPlatformDevice &platform_device = usable_devices[device_platform_id]; + if (platform_device.platform_name != platform_name || + platform_device.device_name != device_name) { + return false; + } + + cl_platform_id platform = platform_device.platform_id; + cl_device_id device = platform_device.device_id; + const cl_context_properties context_props[] = { + CL_CONTEXT_PLATFORM, (cl_context_properties)platform, 0, 0}; + + cl_int err; + cl_context context = clCreateContext(context_props, 1, &device, NULL, NULL, &err); + if (err != CL_SUCCESS) { + return false; + } + + string source = get_program_source(kernel_file); + size_t source_len = source.size(); + const char *source_str = source.c_str(); + cl_program program = clCreateProgramWithSource(context, 1, &source_str, &source_len, &err); + bool result = false; + + if (err == CL_SUCCESS) { + err = clBuildProgram(program, 0, NULL, build_options.c_str(), NULL, NULL); + + if (err == CL_SUCCESS) { + size_t size = 0; + clGetProgramInfo(program, CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &size, NULL); + if (size > 0) { + vector<uint8_t> binary(size); + uint8_t *bytes = &binary[0]; + clGetProgramInfo(program, CL_PROGRAM_BINARIES, sizeof(uint8_t *), &bytes, NULL); + result = path_write_binary(binary_path, binary); + } + } + clReleaseProgram(program); + } + + clReleaseContext(context); + + return result; } -bool OpenCLDevice::OpenCLProgram::load_binary(const string& clbin, - const string *debug_src) +bool OpenCLDevice::OpenCLProgram::load_binary(const string &clbin, const string *debug_src) { - /* read binary into memory */ - vector<uint8_t> binary; + /* read binary into memory */ + vector<uint8_t> binary; - if(!path_read_binary(clbin, binary)) { - add_error(string_printf("OpenCL failed to read cached binary %s.", clbin.c_str())); - return false; - } + if (!path_read_binary(clbin, binary)) { + add_error(string_printf("OpenCL failed to read cached binary %s.", clbin.c_str())); + return false; + } - /* create program */ - cl_int status, ciErr; - size_t size = binary.size(); - const uint8_t *bytes = &binary[0]; + /* create program */ + cl_int status, ciErr; + size_t size = binary.size(); + const uint8_t *bytes = &binary[0]; - program = clCreateProgramWithBinary(device->cxContext, 1, &device->cdDevice, - &size, &bytes, &status, &ciErr); + program = clCreateProgramWithBinary( + device->cxContext, 1, &device->cdDevice, &size, &bytes, &status, &ciErr); - if(status != CL_SUCCESS || ciErr != CL_SUCCESS) { - add_error(string("OpenCL failed create program from cached binary ") + clbin + ": " - + clewErrorString(status) + " " + clewErrorString(ciErr)); - return false; - } + if (status != CL_SUCCESS || ciErr != CL_SUCCESS) { + add_error(string("OpenCL failed create program from cached binary ") + clbin + ": " + + clewErrorString(status) + " " + clewErrorString(ciErr)); + return false; + } - if(!build_kernel(debug_src)) - return false; + if (!build_kernel(debug_src)) + return false; - return true; + return true; } -bool OpenCLDevice::OpenCLProgram::save_binary(const string& clbin) +bool OpenCLDevice::OpenCLProgram::save_binary(const string &clbin) { - size_t size = 0; - clGetProgramInfo(program, CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &size, NULL); + size_t size = 0; + clGetProgramInfo(program, CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &size, NULL); - if(!size) - return false; + if (!size) + return false; - vector<uint8_t> binary(size); - uint8_t *bytes = &binary[0]; + vector<uint8_t> binary(size); + uint8_t *bytes = &binary[0]; - clGetProgramInfo(program, CL_PROGRAM_BINARIES, sizeof(uint8_t*), &bytes, NULL); + clGetProgramInfo(program, CL_PROGRAM_BINARIES, sizeof(uint8_t *), &bytes, NULL); - return path_write_binary(clbin, binary); + return path_write_binary(clbin, binary); } bool OpenCLDevice::OpenCLProgram::load() { - loaded = false; - string device_md5 = device->device_md5_hash(kernel_build_options); - - /* Try to use cached kernel. */ - thread_scoped_lock cache_locker; - ustring cache_key(program_name + device_md5); - program = device->load_cached_kernel(cache_key, - cache_locker); - if (!program) { - add_log(string("OpenCL program ") + program_name + " not found in cache.", true); - - /* need to create source to get md5 */ - string source = get_program_source(kernel_file); - - string basename = "cycles_kernel_" + program_name + "_" + device_md5 + "_" + util_md5_string(source); - basename = path_cache_get(path_join("kernels", basename)); - string clbin = basename + ".clbin"; - - /* If binary kernel exists already, try use it. */ - if(path_exists(clbin) && load_binary(clbin)) { - /* Kernel loaded from binary, nothing to do. */ - add_log(string("Loaded program from ") + clbin + ".", true); - - /* Cache the program. */ - device->store_cached_kernel(program, - cache_key, - cache_locker); - } - else { - add_log(string("OpenCL program ") + program_name + " not found on disk.", true); - cache_locker.unlock(); - } - } - - if (program) { - create_kernels(); - loaded = true; - needs_compiling = false; - } - - return loaded; + loaded = false; + string device_md5 = device->device_md5_hash(kernel_build_options); + + /* Try to use cached kernel. */ + thread_scoped_lock cache_locker; + ustring cache_key(program_name + device_md5); + program = device->load_cached_kernel(cache_key, cache_locker); + if (!program) { + add_log(string("OpenCL program ") + program_name + " not found in cache.", true); + + /* need to create source to get md5 */ + string source = get_program_source(kernel_file); + + string basename = "cycles_kernel_" + program_name + "_" + device_md5 + "_" + + util_md5_string(source); + basename = path_cache_get(path_join("kernels", basename)); + string clbin = basename + ".clbin"; + + /* If binary kernel exists already, try use it. */ + if (path_exists(clbin) && load_binary(clbin)) { + /* Kernel loaded from binary, nothing to do. */ + add_log(string("Loaded program from ") + clbin + ".", true); + + /* Cache the program. */ + device->store_cached_kernel(program, cache_key, cache_locker); + } + else { + add_log(string("OpenCL program ") + program_name + " not found on disk.", true); + cache_locker.unlock(); + } + } + + if (program) { + create_kernels(); + loaded = true; + needs_compiling = false; + } + + return loaded; } void OpenCLDevice::OpenCLProgram::compile() { - assert(device); - - string device_md5 = device->device_md5_hash(kernel_build_options); - - /* Try to use cached kernel. */ - thread_scoped_lock cache_locker; - ustring cache_key(program_name + device_md5); - program = device->load_cached_kernel(cache_key, - cache_locker); - - if (!program) - { - - add_log(string("OpenCL program ") + program_name + " not found in cache.", true); - - /* need to create source to get md5 */ - string source = get_program_source(kernel_file); - - string basename = "cycles_kernel_" + program_name + "_" + device_md5 + "_" + util_md5_string(source); - basename = path_cache_get(path_join("kernels", basename)); - string clbin = basename + ".clbin"; - - /* path to preprocessed source for debugging */ - string clsrc, *debug_src = NULL; - - if(OpenCLInfo::use_debug()) { - clsrc = basename + ".cl"; - debug_src = &clsrc; - } - - /* If binary kernel exists already, try use it. */ - if(compile_separate(clbin)) { - add_log(string("Built and loaded program from ") + clbin + ".", true); - loaded = true; - } - else { - add_log(string("Separate-process building of ") + clbin + " failed, will fall back to regular building.", true); - - /* If does not exist or loading binary failed, compile kernel. */ - if(!compile_kernel(debug_src)) { - needs_compiling = false; - return; - } - - /* Save binary for reuse. */ - if(!save_binary(clbin)) { - add_log(string("Saving compiled OpenCL kernel to ") + clbin + " failed!", true); - } - } - - /* Cache the program. */ - device->store_cached_kernel(program, - cache_key, - cache_locker); - } - - create_kernels(); - needs_compiling = false; - loaded = true; + assert(device); + + string device_md5 = device->device_md5_hash(kernel_build_options); + + /* Try to use cached kernel. */ + thread_scoped_lock cache_locker; + ustring cache_key(program_name + device_md5); + program = device->load_cached_kernel(cache_key, cache_locker); + + if (!program) { + + add_log(string("OpenCL program ") + program_name + " not found in cache.", true); + + /* need to create source to get md5 */ + string source = get_program_source(kernel_file); + + string basename = "cycles_kernel_" + program_name + "_" + device_md5 + "_" + + util_md5_string(source); + basename = path_cache_get(path_join("kernels", basename)); + string clbin = basename + ".clbin"; + + /* path to preprocessed source for debugging */ + string clsrc, *debug_src = NULL; + + if (OpenCLInfo::use_debug()) { + clsrc = basename + ".cl"; + debug_src = &clsrc; + } + + /* If binary kernel exists already, try use it. */ + if (compile_separate(clbin)) { + add_log(string("Built and loaded program from ") + clbin + ".", true); + loaded = true; + } + else { + add_log(string("Separate-process building of ") + clbin + + " failed, will fall back to regular building.", + true); + + /* If does not exist or loading binary failed, compile kernel. */ + if (!compile_kernel(debug_src)) { + needs_compiling = false; + return; + } + + /* Save binary for reuse. */ + if (!save_binary(clbin)) { + add_log(string("Saving compiled OpenCL kernel to ") + clbin + " failed!", true); + } + } + + /* Cache the program. */ + device->store_cached_kernel(program, cache_key, cache_locker); + } + + create_kernels(); + needs_compiling = false; + loaded = true; } void OpenCLDevice::OpenCLProgram::create_kernels() { - for(map<ustring, cl_kernel>::iterator kernel = kernels.begin(); kernel != kernels.end(); ++kernel) { - assert(kernel->second == NULL); - cl_int ciErr; - string name = "kernel_ocl_" + kernel->first.string(); - kernel->second = clCreateKernel(program, name.c_str(), &ciErr); - if(device->opencl_error(ciErr)) { - add_error(string("Error getting kernel ") + name + " from program " + program_name + ": " + clewErrorString(ciErr)); - return; - } - } + for (map<ustring, cl_kernel>::iterator kernel = kernels.begin(); kernel != kernels.end(); + ++kernel) { + assert(kernel->second == NULL); + cl_int ciErr; + string name = "kernel_ocl_" + kernel->first.string(); + kernel->second = clCreateKernel(program, name.c_str(), &ciErr); + if (device->opencl_error(ciErr)) { + add_error(string("Error getting kernel ") + name + " from program " + program_name + ": " + + clewErrorString(ciErr)); + return; + } + } } bool OpenCLDevice::OpenCLProgram::wait_for_availability() { - add_log(string("Waiting for availability of ") + program_name + ".", true); - while (needs_compiling) { - time_sleep(0.1); - } - return loaded; + add_log(string("Waiting for availability of ") + program_name + ".", true); + while (needs_compiling) { + time_sleep(0.1); + } + return loaded; } void OpenCLDevice::OpenCLProgram::report_error() { - /* If loaded is true, there was no error. */ - if(loaded) return; - /* if use_stdout is true, the error was already reported. */ - if(use_stdout) return; - - cerr << error_msg << endl; - if(!compile_output.empty()) { - cerr << "OpenCL kernel build output for " << program_name << ":" << endl; - cerr << compile_output << endl; - } + /* If loaded is true, there was no error. */ + if (loaded) + return; + /* if use_stdout is true, the error was already reported. */ + if (use_stdout) + return; + + cerr << error_msg << endl; + if (!compile_output.empty()) { + cerr << "OpenCL kernel build output for " << program_name << ":" << endl; + cerr << compile_output << endl; + } } cl_kernel OpenCLDevice::OpenCLProgram::operator()() { - assert(kernels.size() == 1); - return kernels.begin()->second; + assert(kernels.size() == 1); + return kernels.begin()->second; } cl_kernel OpenCLDevice::OpenCLProgram::operator()(ustring name) { - assert(kernels.count(name)); - return kernels[name]; + assert(kernels.count(name)); + return kernels[name]; } cl_device_type OpenCLInfo::device_type() { - switch(DebugFlags().opencl.device_type) - { - case DebugFlags::OpenCL::DEVICE_NONE: - return 0; - case DebugFlags::OpenCL::DEVICE_ALL: - return CL_DEVICE_TYPE_ALL; - case DebugFlags::OpenCL::DEVICE_DEFAULT: - return CL_DEVICE_TYPE_DEFAULT; - case DebugFlags::OpenCL::DEVICE_CPU: - return CL_DEVICE_TYPE_CPU; - case DebugFlags::OpenCL::DEVICE_GPU: - return CL_DEVICE_TYPE_GPU; - case DebugFlags::OpenCL::DEVICE_ACCELERATOR: - return CL_DEVICE_TYPE_ACCELERATOR; - default: - return CL_DEVICE_TYPE_ALL; - } + switch (DebugFlags().opencl.device_type) { + case DebugFlags::OpenCL::DEVICE_NONE: + return 0; + case DebugFlags::OpenCL::DEVICE_ALL: + return CL_DEVICE_TYPE_ALL; + case DebugFlags::OpenCL::DEVICE_DEFAULT: + return CL_DEVICE_TYPE_DEFAULT; + case DebugFlags::OpenCL::DEVICE_CPU: + return CL_DEVICE_TYPE_CPU; + case DebugFlags::OpenCL::DEVICE_GPU: + return CL_DEVICE_TYPE_GPU; + case DebugFlags::OpenCL::DEVICE_ACCELERATOR: + return CL_DEVICE_TYPE_ACCELERATOR; + default: + return CL_DEVICE_TYPE_ALL; + } } bool OpenCLInfo::use_debug() { - return DebugFlags().opencl.debug; + return DebugFlags().opencl.debug; } -bool OpenCLInfo::device_supported(const string& platform_name, - const cl_device_id device_id) +bool OpenCLInfo::device_supported(const string &platform_name, const cl_device_id device_id) { - cl_device_type device_type; - if(!get_device_type(device_id, &device_type)) { - return false; - } - string device_name; - if(!get_device_name(device_id, &device_name)) { - return false; - } - - int driver_major = 0; - int driver_minor = 0; - if(!get_driver_version(device_id, &driver_major, &driver_minor)) { - return false; - } - VLOG(3) << "OpenCL driver version " << driver_major << "." << driver_minor; - - /* It is possible tyo have Iris GPU on AMD/Apple OpenCL framework - * (aka, it will not be on Intel framework). This isn't supported - * and needs an explicit blacklist. - */ - if(strstr(device_name.c_str(), "Iris")) { - return false; - } - if(platform_name == "AMD Accelerated Parallel Processing" && - device_type == CL_DEVICE_TYPE_GPU) - { - if(driver_major < 2236) { - VLOG(1) << "AMD driver version " << driver_major << "." << driver_minor << " not supported."; - return false; - } - const char *blacklist[] = { - /* GCN 1 */ - "Tahiti", "Pitcairn", "Capeverde", "Oland", "Hainan", - NULL - }; - for(int i = 0; blacklist[i] != NULL; i++) { - if(device_name == blacklist[i]) { - VLOG(1) << "AMD device " << device_name << " not supported"; - return false; - } - } - return true; - } - if(platform_name == "Apple" && device_type == CL_DEVICE_TYPE_GPU) { - return false; - } - return false; + cl_device_type device_type; + if (!get_device_type(device_id, &device_type)) { + return false; + } + string device_name; + if (!get_device_name(device_id, &device_name)) { + return false; + } + + int driver_major = 0; + int driver_minor = 0; + if (!get_driver_version(device_id, &driver_major, &driver_minor)) { + return false; + } + VLOG(3) << "OpenCL driver version " << driver_major << "." << driver_minor; + + /* It is possible tyo have Iris GPU on AMD/Apple OpenCL framework + * (aka, it will not be on Intel framework). This isn't supported + * and needs an explicit blacklist. + */ + if (strstr(device_name.c_str(), "Iris")) { + return false; + } + if (platform_name == "AMD Accelerated Parallel Processing" && + device_type == CL_DEVICE_TYPE_GPU) { + if (driver_major < 2236) { + VLOG(1) << "AMD driver version " << driver_major << "." << driver_minor << " not supported."; + return false; + } + const char *blacklist[] = {/* GCN 1 */ + "Tahiti", + "Pitcairn", + "Capeverde", + "Oland", + "Hainan", + NULL}; + for (int i = 0; blacklist[i] != NULL; i++) { + if (device_name == blacklist[i]) { + VLOG(1) << "AMD device " << device_name << " not supported"; + return false; + } + } + return true; + } + if (platform_name == "Apple" && device_type == CL_DEVICE_TYPE_GPU) { + return false; + } + return false; } -bool OpenCLInfo::platform_version_check(cl_platform_id platform, - string *error) +bool OpenCLInfo::platform_version_check(cl_platform_id platform, string *error) { - const int req_major = 1, req_minor = 1; - int major, minor; - char version[256]; - clGetPlatformInfo(platform, - CL_PLATFORM_VERSION, - sizeof(version), - &version, - NULL); - if(sscanf(version, "OpenCL %d.%d", &major, &minor) < 2) { - if(error != NULL) { - *error = string_printf("OpenCL: failed to parse platform version string (%s).", version); - } - return false; - } - if(!((major == req_major && minor >= req_minor) || (major > req_major))) { - if(error != NULL) { - *error = string_printf("OpenCL: platform version 1.1 or later required, found %d.%d", major, minor); - } - return false; - } - if(error != NULL) { - *error = ""; - } - return true; + const int req_major = 1, req_minor = 1; + int major, minor; + char version[256]; + clGetPlatformInfo(platform, CL_PLATFORM_VERSION, sizeof(version), &version, NULL); + if (sscanf(version, "OpenCL %d.%d", &major, &minor) < 2) { + if (error != NULL) { + *error = string_printf("OpenCL: failed to parse platform version string (%s).", version); + } + return false; + } + if (!((major == req_major && minor >= req_minor) || (major > req_major))) { + if (error != NULL) { + *error = string_printf( + "OpenCL: platform version 1.1 or later required, found %d.%d", major, minor); + } + return false; + } + if (error != NULL) { + *error = ""; + } + return true; } -bool OpenCLInfo::device_version_check(cl_device_id device, - string *error) +bool OpenCLInfo::device_version_check(cl_device_id device, string *error) { - const int req_major = 1, req_minor = 1; - int major, minor; - char version[256]; - clGetDeviceInfo(device, - CL_DEVICE_OPENCL_C_VERSION, - sizeof(version), - &version, - NULL); - if(sscanf(version, "OpenCL C %d.%d", &major, &minor) < 2) { - if(error != NULL) { - *error = string_printf("OpenCL: failed to parse OpenCL C version string (%s).", version); - } - return false; - } - if(!((major == req_major && minor >= req_minor) || (major > req_major))) { - if(error != NULL) { - *error = string_printf("OpenCL: C version 1.1 or later required, found %d.%d", major, minor); - } - return false; - } - if(error != NULL) { - *error = ""; - } - return true; + const int req_major = 1, req_minor = 1; + int major, minor; + char version[256]; + clGetDeviceInfo(device, CL_DEVICE_OPENCL_C_VERSION, sizeof(version), &version, NULL); + if (sscanf(version, "OpenCL C %d.%d", &major, &minor) < 2) { + if (error != NULL) { + *error = string_printf("OpenCL: failed to parse OpenCL C version string (%s).", version); + } + return false; + } + if (!((major == req_major && minor >= req_minor) || (major > req_major))) { + if (error != NULL) { + *error = string_printf("OpenCL: C version 1.1 or later required, found %d.%d", major, minor); + } + return false; + } + if (error != NULL) { + *error = ""; + } + return true; } -string OpenCLInfo::get_hardware_id(const string& platform_name, cl_device_id device_id) +string OpenCLInfo::get_hardware_id(const string &platform_name, cl_device_id device_id) { - if(platform_name == "AMD Accelerated Parallel Processing" || platform_name == "Apple") { - /* Use cl_amd_device_topology extension. */ - cl_char topology[24]; - if(clGetDeviceInfo(device_id, 0x4037, sizeof(topology), topology, NULL) == CL_SUCCESS && topology[0] == 1) { - return string_printf("%02x:%02x.%01x", - (unsigned int)topology[21], - (unsigned int)topology[22], - (unsigned int)topology[23]); - } - } - else if(platform_name == "NVIDIA CUDA") { - /* Use two undocumented options of the cl_nv_device_attribute_query extension. */ - cl_int bus_id, slot_id; - if(clGetDeviceInfo(device_id, 0x4008, sizeof(cl_int), &bus_id, NULL) == CL_SUCCESS && - clGetDeviceInfo(device_id, 0x4009, sizeof(cl_int), &slot_id, NULL) == CL_SUCCESS) { - return string_printf("%02x:%02x.%01x", - (unsigned int)(bus_id), - (unsigned int)(slot_id >> 3), - (unsigned int)(slot_id & 0x7)); - } - } - /* No general way to get a hardware ID from OpenCL => give up. */ - return ""; + if (platform_name == "AMD Accelerated Parallel Processing" || platform_name == "Apple") { + /* Use cl_amd_device_topology extension. */ + cl_char topology[24]; + if (clGetDeviceInfo(device_id, 0x4037, sizeof(topology), topology, NULL) == CL_SUCCESS && + topology[0] == 1) { + return string_printf("%02x:%02x.%01x", + (unsigned int)topology[21], + (unsigned int)topology[22], + (unsigned int)topology[23]); + } + } + else if (platform_name == "NVIDIA CUDA") { + /* Use two undocumented options of the cl_nv_device_attribute_query extension. */ + cl_int bus_id, slot_id; + if (clGetDeviceInfo(device_id, 0x4008, sizeof(cl_int), &bus_id, NULL) == CL_SUCCESS && + clGetDeviceInfo(device_id, 0x4009, sizeof(cl_int), &slot_id, NULL) == CL_SUCCESS) { + return string_printf("%02x:%02x.%01x", + (unsigned int)(bus_id), + (unsigned int)(slot_id >> 3), + (unsigned int)(slot_id & 0x7)); + } + } + /* No general way to get a hardware ID from OpenCL => give up. */ + return ""; } -void OpenCLInfo::get_usable_devices(vector<OpenCLPlatformDevice> *usable_devices, - bool force_all) +void OpenCLInfo::get_usable_devices(vector<OpenCLPlatformDevice> *usable_devices, bool force_all) { - const cl_device_type device_type = OpenCLInfo::device_type(); - static bool first_time = true; -#define FIRST_VLOG(severity) if(first_time) VLOG(severity) - - usable_devices->clear(); - - if(device_type == 0) { - FIRST_VLOG(2) << "OpenCL devices are forced to be disabled."; - first_time = false; - return; - } - - cl_int error; - vector<cl_device_id> device_ids; - vector<cl_platform_id> platform_ids; - - /* Get platforms. */ - if(!get_platforms(&platform_ids, &error)) { - FIRST_VLOG(2) << "Error fetching platforms:" - << string(clewErrorString(error)); - first_time = false; - return; - } - if(platform_ids.size() == 0) { - FIRST_VLOG(2) << "No OpenCL platforms were found."; - first_time = false; - return; - } - /* Devices are numbered consecutively across platforms. */ - for(int platform = 0; platform < platform_ids.size(); platform++) { - cl_platform_id platform_id = platform_ids[platform]; - string platform_name; - if(!get_platform_name(platform_id, &platform_name)) { - FIRST_VLOG(2) << "Failed to get platform name, ignoring."; - continue; - } - FIRST_VLOG(2) << "Enumerating devices for platform " - << platform_name << "."; - if(!platform_version_check(platform_id)) { - FIRST_VLOG(2) << "Ignoring platform " << platform_name - << " due to too old compiler version."; - continue; - } - if(!get_platform_devices(platform_id, - device_type, - &device_ids, - &error)) - { - FIRST_VLOG(2) << "Ignoring platform " << platform_name - << ", failed to fetch of devices: " - << string(clewErrorString(error)); - continue; - } - if(device_ids.size() == 0) { - FIRST_VLOG(2) << "Ignoring platform " << platform_name - << ", it has no devices."; - continue; - } - for(int num = 0; num < device_ids.size(); num++) { - const cl_device_id device_id = device_ids[num]; - string device_name; - if(!get_device_name(device_id, &device_name, &error)) { - FIRST_VLOG(2) << "Failed to fetch device name: " - << string(clewErrorString(error)) - << ", ignoring."; - continue; - } - if(!device_version_check(device_id)) { - FIRST_VLOG(2) << "Ignoring device " << device_name - << " due to old compiler version."; - continue; - } - if(force_all || - device_supported(platform_name, device_id)) - { - cl_device_type device_type; - if(!get_device_type(device_id, &device_type, &error)) { - FIRST_VLOG(2) << "Ignoring device " << device_name - << ", failed to fetch device type:" - << string(clewErrorString(error)); - continue; - } - string readable_device_name = - get_readable_device_name(device_id); - if(readable_device_name != device_name) { - FIRST_VLOG(2) << "Using more readable device name: " - << readable_device_name; - } - FIRST_VLOG(2) << "Adding new device " - << readable_device_name << "."; - string hardware_id = get_hardware_id(platform_name, device_id); - string device_extensions = get_device_extensions(device_id); - usable_devices->push_back(OpenCLPlatformDevice( - platform_id, - platform_name, - device_id, - device_type, - readable_device_name, - hardware_id, - device_extensions)); - } - else { - FIRST_VLOG(2) << "Ignoring device " << device_name - << ", not officially supported yet."; - } - } - } - first_time = false; + const cl_device_type device_type = OpenCLInfo::device_type(); + static bool first_time = true; +# define FIRST_VLOG(severity) \ + if (first_time) \ + VLOG(severity) + + usable_devices->clear(); + + if (device_type == 0) { + FIRST_VLOG(2) << "OpenCL devices are forced to be disabled."; + first_time = false; + return; + } + + cl_int error; + vector<cl_device_id> device_ids; + vector<cl_platform_id> platform_ids; + + /* Get platforms. */ + if (!get_platforms(&platform_ids, &error)) { + FIRST_VLOG(2) << "Error fetching platforms:" << string(clewErrorString(error)); + first_time = false; + return; + } + if (platform_ids.size() == 0) { + FIRST_VLOG(2) << "No OpenCL platforms were found."; + first_time = false; + return; + } + /* Devices are numbered consecutively across platforms. */ + for (int platform = 0; platform < platform_ids.size(); platform++) { + cl_platform_id platform_id = platform_ids[platform]; + string platform_name; + if (!get_platform_name(platform_id, &platform_name)) { + FIRST_VLOG(2) << "Failed to get platform name, ignoring."; + continue; + } + FIRST_VLOG(2) << "Enumerating devices for platform " << platform_name << "."; + if (!platform_version_check(platform_id)) { + FIRST_VLOG(2) << "Ignoring platform " << platform_name + << " due to too old compiler version."; + continue; + } + if (!get_platform_devices(platform_id, device_type, &device_ids, &error)) { + FIRST_VLOG(2) << "Ignoring platform " << platform_name + << ", failed to fetch of devices: " << string(clewErrorString(error)); + continue; + } + if (device_ids.size() == 0) { + FIRST_VLOG(2) << "Ignoring platform " << platform_name << ", it has no devices."; + continue; + } + for (int num = 0; num < device_ids.size(); num++) { + const cl_device_id device_id = device_ids[num]; + string device_name; + if (!get_device_name(device_id, &device_name, &error)) { + FIRST_VLOG(2) << "Failed to fetch device name: " << string(clewErrorString(error)) + << ", ignoring."; + continue; + } + if (!device_version_check(device_id)) { + FIRST_VLOG(2) << "Ignoring device " << device_name << " due to old compiler version."; + continue; + } + if (force_all || device_supported(platform_name, device_id)) { + cl_device_type device_type; + if (!get_device_type(device_id, &device_type, &error)) { + FIRST_VLOG(2) << "Ignoring device " << device_name + << ", failed to fetch device type:" << string(clewErrorString(error)); + continue; + } + string readable_device_name = get_readable_device_name(device_id); + if (readable_device_name != device_name) { + FIRST_VLOG(2) << "Using more readable device name: " << readable_device_name; + } + FIRST_VLOG(2) << "Adding new device " << readable_device_name << "."; + string hardware_id = get_hardware_id(platform_name, device_id); + string device_extensions = get_device_extensions(device_id); + usable_devices->push_back(OpenCLPlatformDevice(platform_id, + platform_name, + device_id, + device_type, + readable_device_name, + hardware_id, + device_extensions)); + } + else { + FIRST_VLOG(2) << "Ignoring device " << device_name << ", not officially supported yet."; + } + } + } + first_time = false; } -bool OpenCLInfo::get_platforms(vector<cl_platform_id> *platform_ids, - cl_int *error) +bool OpenCLInfo::get_platforms(vector<cl_platform_id> *platform_ids, cl_int *error) { - /* Reset from possible previous state. */ - platform_ids->resize(0); - cl_uint num_platforms; - if(!get_num_platforms(&num_platforms, error)) { - return false; - } - /* Get actual platforms. */ - cl_int err; - platform_ids->resize(num_platforms); - if((err = clGetPlatformIDs(num_platforms, - &platform_ids->at(0), - NULL)) != CL_SUCCESS) { - if(error != NULL) { - *error = err; - } - return false; - } - if(error != NULL) { - *error = CL_SUCCESS; - } - return true; + /* Reset from possible previous state. */ + platform_ids->resize(0); + cl_uint num_platforms; + if (!get_num_platforms(&num_platforms, error)) { + return false; + } + /* Get actual platforms. */ + cl_int err; + platform_ids->resize(num_platforms); + if ((err = clGetPlatformIDs(num_platforms, &platform_ids->at(0), NULL)) != CL_SUCCESS) { + if (error != NULL) { + *error = err; + } + return false; + } + if (error != NULL) { + *error = CL_SUCCESS; + } + return true; } vector<cl_platform_id> OpenCLInfo::get_platforms() { - vector<cl_platform_id> platform_ids; - get_platforms(&platform_ids); - return platform_ids; + vector<cl_platform_id> platform_ids; + get_platforms(&platform_ids); + return platform_ids; } bool OpenCLInfo::get_num_platforms(cl_uint *num_platforms, cl_int *error) { - cl_int err; - if((err = clGetPlatformIDs(0, NULL, num_platforms)) != CL_SUCCESS) { - if(error != NULL) { - *error = err; - } - *num_platforms = 0; - return false; - } - if(error != NULL) { - *error = CL_SUCCESS; - } - return true; + cl_int err; + if ((err = clGetPlatformIDs(0, NULL, num_platforms)) != CL_SUCCESS) { + if (error != NULL) { + *error = err; + } + *num_platforms = 0; + return false; + } + if (error != NULL) { + *error = CL_SUCCESS; + } + return true; } cl_uint OpenCLInfo::get_num_platforms() { - cl_uint num_platforms; - if(!get_num_platforms(&num_platforms)) { - return 0; - } - return num_platforms; + cl_uint num_platforms; + if (!get_num_platforms(&num_platforms)) { + return 0; + } + return num_platforms; } -bool OpenCLInfo::get_platform_name(cl_platform_id platform_id, - string *platform_name) +bool OpenCLInfo::get_platform_name(cl_platform_id platform_id, string *platform_name) { - char buffer[256]; - if(clGetPlatformInfo(platform_id, - CL_PLATFORM_NAME, - sizeof(buffer), - &buffer, - NULL) != CL_SUCCESS) - { - *platform_name = ""; - return false; - } - *platform_name = buffer; - return true; + char buffer[256]; + if (clGetPlatformInfo(platform_id, CL_PLATFORM_NAME, sizeof(buffer), &buffer, NULL) != + CL_SUCCESS) { + *platform_name = ""; + return false; + } + *platform_name = buffer; + return true; } string OpenCLInfo::get_platform_name(cl_platform_id platform_id) { - string platform_name; - if(!get_platform_name(platform_id, &platform_name)) { - return ""; - } - return platform_name; + string platform_name; + if (!get_platform_name(platform_id, &platform_name)) { + return ""; + } + return platform_name; } bool OpenCLInfo::get_num_platform_devices(cl_platform_id platform_id, @@ -1076,266 +1034,222 @@ bool OpenCLInfo::get_num_platform_devices(cl_platform_id platform_id, cl_uint *num_devices, cl_int *error) { - cl_int err; - if((err = clGetDeviceIDs(platform_id, - device_type, - 0, - NULL, - num_devices)) != CL_SUCCESS) - { - if(error != NULL) { - *error = err; - } - *num_devices = 0; - return false; - } - if(error != NULL) { - *error = CL_SUCCESS; - } - return true; + cl_int err; + if ((err = clGetDeviceIDs(platform_id, device_type, 0, NULL, num_devices)) != CL_SUCCESS) { + if (error != NULL) { + *error = err; + } + *num_devices = 0; + return false; + } + if (error != NULL) { + *error = CL_SUCCESS; + } + return true; } cl_uint OpenCLInfo::get_num_platform_devices(cl_platform_id platform_id, cl_device_type device_type) { - cl_uint num_devices; - if(!get_num_platform_devices(platform_id, - device_type, - &num_devices)) - { - return 0; - } - return num_devices; + cl_uint num_devices; + if (!get_num_platform_devices(platform_id, device_type, &num_devices)) { + return 0; + } + return num_devices; } bool OpenCLInfo::get_platform_devices(cl_platform_id platform_id, cl_device_type device_type, vector<cl_device_id> *device_ids, - cl_int* error) + cl_int *error) { - /* Reset from possible previous state. */ - device_ids->resize(0); - /* Get number of devices to pre-allocate memory. */ - cl_uint num_devices; - if(!get_num_platform_devices(platform_id, - device_type, - &num_devices, - error)) - { - return false; - } - /* Get actual device list. */ - device_ids->resize(num_devices); - cl_int err; - if((err = clGetDeviceIDs(platform_id, - device_type, - num_devices, - &device_ids->at(0), - NULL)) != CL_SUCCESS) - { - if(error != NULL) { - *error = err; - } - return false; - } - if(error != NULL) { - *error = CL_SUCCESS; - } - return true; + /* Reset from possible previous state. */ + device_ids->resize(0); + /* Get number of devices to pre-allocate memory. */ + cl_uint num_devices; + if (!get_num_platform_devices(platform_id, device_type, &num_devices, error)) { + return false; + } + /* Get actual device list. */ + device_ids->resize(num_devices); + cl_int err; + if ((err = clGetDeviceIDs(platform_id, device_type, num_devices, &device_ids->at(0), NULL)) != + CL_SUCCESS) { + if (error != NULL) { + *error = err; + } + return false; + } + if (error != NULL) { + *error = CL_SUCCESS; + } + return true; } vector<cl_device_id> OpenCLInfo::get_platform_devices(cl_platform_id platform_id, cl_device_type device_type) { - vector<cl_device_id> devices; - get_platform_devices(platform_id, device_type, &devices); - return devices; + vector<cl_device_id> devices; + get_platform_devices(platform_id, device_type, &devices); + return devices; } -bool OpenCLInfo::get_device_name(cl_device_id device_id, - string *device_name, - cl_int* error) +bool OpenCLInfo::get_device_name(cl_device_id device_id, string *device_name, cl_int *error) { - char buffer[1024]; - cl_int err; - if((err = clGetDeviceInfo(device_id, - CL_DEVICE_NAME, - sizeof(buffer), - &buffer, - NULL)) != CL_SUCCESS) - { - if(error != NULL) { - *error = err; - } - *device_name = ""; - return false; - } - if(error != NULL) { - *error = CL_SUCCESS; - } - *device_name = buffer; - return true; + char buffer[1024]; + cl_int err; + if ((err = clGetDeviceInfo(device_id, CL_DEVICE_NAME, sizeof(buffer), &buffer, NULL)) != + CL_SUCCESS) { + if (error != NULL) { + *error = err; + } + *device_name = ""; + return false; + } + if (error != NULL) { + *error = CL_SUCCESS; + } + *device_name = buffer; + return true; } string OpenCLInfo::get_device_name(cl_device_id device_id) { - string device_name; - if(!get_device_name(device_id, &device_name)) { - return ""; - } - return device_name; + string device_name; + if (!get_device_name(device_id, &device_name)) { + return ""; + } + return device_name; } bool OpenCLInfo::get_device_extensions(cl_device_id device_id, - string *device_extensions, - cl_int* error) + string *device_extensions, + cl_int *error) { - char buffer[1024]; - cl_int err; - if((err = clGetDeviceInfo(device_id, - CL_DEVICE_EXTENSIONS, - sizeof(buffer), - &buffer, - NULL)) != CL_SUCCESS) - { - if(error != NULL) { - *error = err; - } - *device_extensions = ""; - return false; - } - if(error != NULL) { - *error = CL_SUCCESS; - } - *device_extensions = buffer; - return true; + char buffer[1024]; + cl_int err; + if ((err = clGetDeviceInfo(device_id, CL_DEVICE_EXTENSIONS, sizeof(buffer), &buffer, NULL)) != + CL_SUCCESS) { + if (error != NULL) { + *error = err; + } + *device_extensions = ""; + return false; + } + if (error != NULL) { + *error = CL_SUCCESS; + } + *device_extensions = buffer; + return true; } string OpenCLInfo::get_device_extensions(cl_device_id device_id) { - string device_extensions; - if(!get_device_extensions(device_id, &device_extensions)) { - return ""; - } - return device_extensions; + string device_extensions; + if (!get_device_extensions(device_id, &device_extensions)) { + return ""; + } + return device_extensions; } bool OpenCLInfo::get_device_type(cl_device_id device_id, cl_device_type *device_type, - cl_int* error) + cl_int *error) { - cl_int err; - if((err = clGetDeviceInfo(device_id, - CL_DEVICE_TYPE, - sizeof(cl_device_type), - device_type, - NULL)) != CL_SUCCESS) - { - if(error != NULL) { - *error = err; - } - *device_type = 0; - return false; - } - if(error != NULL) { - *error = CL_SUCCESS; - } - return true; + cl_int err; + if ((err = clGetDeviceInfo( + device_id, CL_DEVICE_TYPE, sizeof(cl_device_type), device_type, NULL)) != CL_SUCCESS) { + if (error != NULL) { + *error = err; + } + *device_type = 0; + return false; + } + if (error != NULL) { + *error = CL_SUCCESS; + } + return true; } cl_device_type OpenCLInfo::get_device_type(cl_device_id device_id) { - cl_device_type device_type; - if(!get_device_type(device_id, &device_type)) { - return 0; - } - return device_type; + cl_device_type device_type; + if (!get_device_type(device_id, &device_type)) { + return 0; + } + return device_type; } string OpenCLInfo::get_readable_device_name(cl_device_id device_id) { - string name = ""; - char board_name[1024]; - size_t length = 0; - if(clGetDeviceInfo(device_id, - CL_DEVICE_BOARD_NAME_AMD, - sizeof(board_name), - &board_name, - &length) == CL_SUCCESS) - { - if(length != 0 && board_name[0] != '\0') { - name = board_name; - } - } - - /* Fallback to standard device name API. */ - if(name.empty()) { - name = get_device_name(device_id); - } - - /* Special exception for AMD Vega, need to be able to tell - * Vega 56 from 64 apart. - */ - if(name == "Radeon RX Vega") { - cl_int max_compute_units = 0; - if(clGetDeviceInfo(device_id, - CL_DEVICE_MAX_COMPUTE_UNITS, - sizeof(max_compute_units), - &max_compute_units, - NULL) == CL_SUCCESS) - { - name += " " + to_string(max_compute_units); - } - } - - /* Distinguish from our native CPU device. */ - if(get_device_type(device_id) & CL_DEVICE_TYPE_CPU) { - name += " (OpenCL)"; - } - - return name; + string name = ""; + char board_name[1024]; + size_t length = 0; + if (clGetDeviceInfo( + device_id, CL_DEVICE_BOARD_NAME_AMD, sizeof(board_name), &board_name, &length) == + CL_SUCCESS) { + if (length != 0 && board_name[0] != '\0') { + name = board_name; + } + } + + /* Fallback to standard device name API. */ + if (name.empty()) { + name = get_device_name(device_id); + } + + /* Special exception for AMD Vega, need to be able to tell + * Vega 56 from 64 apart. + */ + if (name == "Radeon RX Vega") { + cl_int max_compute_units = 0; + if (clGetDeviceInfo(device_id, + CL_DEVICE_MAX_COMPUTE_UNITS, + sizeof(max_compute_units), + &max_compute_units, + NULL) == CL_SUCCESS) { + name += " " + to_string(max_compute_units); + } + } + + /* Distinguish from our native CPU device. */ + if (get_device_type(device_id) & CL_DEVICE_TYPE_CPU) { + name += " (OpenCL)"; + } + + return name; } -bool OpenCLInfo::get_driver_version(cl_device_id device_id, - int *major, - int *minor, - cl_int* error) +bool OpenCLInfo::get_driver_version(cl_device_id device_id, int *major, int *minor, cl_int *error) { - char buffer[1024]; - cl_int err; - if((err = clGetDeviceInfo(device_id, - CL_DRIVER_VERSION, - sizeof(buffer), - &buffer, - NULL)) != CL_SUCCESS) - { - if(error != NULL) { - *error = err; - } - return false; - } - if(error != NULL) { - *error = CL_SUCCESS; - } - if(sscanf(buffer, "%d.%d", major, minor) < 2) { - VLOG(1) << string_printf("OpenCL: failed to parse driver version string (%s).", buffer); - return false; - } - return true; + char buffer[1024]; + cl_int err; + if ((err = clGetDeviceInfo(device_id, CL_DRIVER_VERSION, sizeof(buffer), &buffer, NULL)) != + CL_SUCCESS) { + if (error != NULL) { + *error = err; + } + return false; + } + if (error != NULL) { + *error = CL_SUCCESS; + } + if (sscanf(buffer, "%d.%d", major, minor) < 2) { + VLOG(1) << string_printf("OpenCL: failed to parse driver version string (%s).", buffer); + return false; + } + return true; } int OpenCLInfo::mem_sub_ptr_alignment(cl_device_id device_id) { - int base_align_bits; - if(clGetDeviceInfo(device_id, - CL_DEVICE_MEM_BASE_ADDR_ALIGN, - sizeof(int), - &base_align_bits, - NULL) == CL_SUCCESS) - { - return base_align_bits/8; - } - return 1; + int base_align_bits; + if (clGetDeviceInfo( + device_id, CL_DEVICE_MEM_BASE_ADDR_ALIGN, sizeof(int), &base_align_bits, NULL) == + CL_SUCCESS) { + return base_align_bits / 8; + } + return 1; } CCL_NAMESPACE_END |