Commit: 43e843966b0f4174105e10eaa1ea3c0d919c31d6
Author: varunsundar08
Date:   Thu Apr 30 14:38:41 2015 +0530
Branches: cycles_kernel_split
https://developer.blender.org/rB43e843966b0f4174105e10eaa1ea3c0d919c31d6

Use OpenCLCache for megakernel

===================================================================

M       intern/cycles/device/device_opencl.cpp
M       intern/cycles/kernel/kernel.cl

===================================================================

diff --git a/intern/cycles/device/device_opencl.cpp 
b/intern/cycles/device/device_opencl.cpp
index b1392fa..6bb862e 100644
--- a/intern/cycles/device/device_opencl.cpp
+++ b/intern/cycles/device/device_opencl.cpp
@@ -123,11 +123,11 @@ static string opencl_kernel_build_options(const string& 
platform, const string *
                build_options += "-D__KERNEL_OPENCL_AMD__ ";
 
        else if(platform == "Intel(R) OpenCL") {
-               build_options += "-D__KERNEL_OPENCL_INTEL_CPU__";
+               build_options += "-D__KERNEL_OPENCL_INTEL_CPU__ ";
 
                /* options for gdb source level kernel debugging. this 
segfaults on linux currently */
                if(opencl_kernel_use_debug() && debug_src)
-                       build_options += "-g -s \"" + *debug_src + "\"";
+                       build_options += "-g -s \"" + *debug_src + "\" ";
        }
 
        if(opencl_kernel_use_debug())
@@ -147,14 +147,18 @@ class OpenCLCache
        {
                thread_mutex *mutex;
                cl_context context;
-               cl_program program;
+               /* cl_program for shader, bake, film_convert kernels (used in 
OpenCLDeviceBase) */
+               cl_program ocl_dev_base_program;
+               /* cl_program for megakernel (used in OpenCLDeviceMegaKernel) */
+               cl_program ocl_dev_megakernel_program;
 
-               Slot() : mutex(NULL), context(NULL), program(NULL) {}
+               Slot() : mutex(NULL), context(NULL), 
ocl_dev_base_program(NULL), ocl_dev_megakernel_program(NULL) {}
 
                Slot(const Slot &rhs)
                        : mutex(rhs.mutex)
                        , context(rhs.context)
-                       , program(rhs.program)
+                       , ocl_dev_base_program(rhs.ocl_dev_base_program)
+                       , 
ocl_dev_megakernel_program(rhs.ocl_dev_megakernel_program)
                {
                        /* copy can only happen in map insert, assert that */
                        assert(mutex == NULL);
@@ -283,10 +287,21 @@ public:
        }
 
        /* see get_something comment */
-       static cl_program get_program(cl_platform_id platform, cl_device_id 
device,
+       static cl_program get_program(cl_platform_id platform, cl_device_id 
device, string program_name,
                thread_scoped_lock &slot_locker)
        {
-               cl_program program = get_something<cl_program>(platform, 
device, &Slot::program, slot_locker);
+               cl_program program = NULL;
+
+               if (program_name == "ocl_dev_base_program") {
+                       /* Get program related to OpenCLDeviceBase */
+                       program = get_something<cl_program>(platform, device, 
&Slot::ocl_dev_base_program, slot_locker);
+               }
+               else if (program_name == "ocl_dev_megakernel_program") {
+                       /* Get program related to megakernel */
+                       program = get_something<cl_program>(platform, device, 
&Slot::ocl_dev_megakernel_program, slot_locker);
+               } else {
+                       fprintf(stderr, "Invalid program name in OpenCLCache 
\n");
+               }
 
                if(!program)
                        return NULL;
@@ -313,10 +328,18 @@ public:
        }
 
        /* see store_something comment */
-       static void store_program(cl_platform_id platform, cl_device_id device, 
cl_program program,
+       static void store_program(cl_platform_id platform, cl_device_id device, 
cl_program program, string program_name,
                thread_scoped_lock &slot_locker)
        {
-               store_something<cl_program>(platform, device, program, 
&Slot::program, slot_locker);
+               if (program_name == "ocl_dev_base_program") {
+                       store_something<cl_program>(platform, device, program, 
&Slot::ocl_dev_base_program, slot_locker);
+               }
+               else if(program_name == "ocl_dev_megakernel_program") {
+                       store_something<cl_program>(platform, device, program, 
&Slot::ocl_dev_megakernel_program, slot_locker);
+               } else {
+                       fprintf(stderr, "Invalid program name in OpenCLCache 
\n");
+                       return;
+               }
 
                /* increment reference count in OpenCL.
                 * The caller is going to release the object when done with it. 
*/
@@ -333,9 +356,11 @@ public:
                thread_scoped_lock cache_lock(self.cache_lock);
 
                foreach(CacheMap::value_type &item, self.cache) {
-                       if(item.second.program != NULL)
-                               clReleaseProgram(item.second.program);
-                       if(item.second.context != NULL)
+                       if (item.second.ocl_dev_base_program != NULL)
+                               
clReleaseProgram(item.second.ocl_dev_base_program);
+                       if (item.second.ocl_dev_megakernel_program != NULL)
+                               
clReleaseProgram(item.second.ocl_dev_megakernel_program);
+                       if (item.second.context != NULL)
                                clReleaseContext(item.second.context);
                }
 
@@ -733,6 +758,199 @@ public:
                }
        }
 
+       bool load_binary(cl_program *program, const string& kernel_path, const 
string& clbin, string custom_kernel_build_options, const string *debug_src = 
NULL)
+       {
+               /* read binary into memory */
+               vector<uint8_t> binary;
+
+               if (!path_read_binary(clbin, binary)) {
+                       opencl_error(string_printf("OpenCL failed to read 
cached binary %s.", clbin.c_str()));
+                       return false;
+               }
+
+               /* create program */
+               cl_int status;
+               size_t size = binary.size();
+               const uint8_t *bytes = &binary[0];
+
+               *program = clCreateProgramWithBinary(cxContext, 1, &cdDevice,
+                       &size, &bytes, &status, &ciErr);
+
+               if (opencl_error(status) || opencl_error(ciErr)) {
+                       opencl_error(string_printf("OpenCL failed create 
program from cached binary %s.", clbin.c_str()));
+                       return false;
+               }
+
+               if (!build_kernel(kernel_path, program, 
custom_kernel_build_options, debug_src))
+                       return false;
+
+               return true;
+       }
+
+       bool save_binary(cl_program *program, const string& clbin) {
+               size_t size = 0;
+               clGetProgramInfo(*program, CL_PROGRAM_BINARY_SIZES, 
sizeof(size_t), &size, NULL);
+
+               if (!size)
+                       return false;
+
+               vector<uint8_t> binary(size);
+               uint8_t *bytes = &binary[0];
+
+               clGetProgramInfo(*program, CL_PROGRAM_BINARIES, 
sizeof(uint8_t*), &bytes, NULL);
+
+               if (!path_write_binary(clbin, binary)) {
+                       opencl_error(string_printf("OpenCL failed to write 
cached binary %s.", clbin.c_str()));
+                       return false;
+               }
+
+               return true;
+       }
+
+       bool build_kernel(const string& /*kernel_path*/,
+               cl_program *kernel_program,
+               string custom_kernel_build_options,
+               const string *debug_src = NULL)
+       {
+               string build_options;
+               build_options = opencl_kernel_build_options(platform_name, 
debug_src) + custom_kernel_build_options;
+
+               ciErr = clBuildProgram(*kernel_program, 0, NULL, 
build_options.c_str(), NULL, NULL);
+
+               /* show warnings even if build is successful */
+               size_t ret_val_size = 0;
+
+               clGetProgramBuildInfo(*kernel_program, cdDevice, 
CL_PROGRAM_BUILD_LOG, 0, NULL, &ret_val_size);
+
+               if (ret_val_size > 1) {
+                       vector<char> build_log(ret_val_size + 1);
+                       clGetProgramBuildInfo(*kernel_program, cdDevice, 
CL_PROGRAM_BUILD_LOG, ret_val_size, &build_log[0], NULL);
+
+                       build_log[ret_val_size] = '\0';
+                       fprintf(stderr, "OpenCL kernel build output:\n");
+                       fprintf(stderr, "%s\n", &build_log[0]);
+               }
+
+               if (ciErr != CL_SUCCESS) {
+                       opencl_error("OpenCL build failed: errors in console");
+                       return false;
+               }
+
+               return true;
+       }
+
+
+       bool compile_kernel(const string& kernel_path,
+               const string& /*kernel_name*/,
+               string source,
+               cl_program *kernel_program,
+               string custom_kernel_build_options,
+               const string *debug_src = NULL)
+       {
+               /* 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, kernel_path);
+
+               if (debug_src)
+                       path_write_text(*debug_src, source);
+               size_t source_len = source.size();
+               const char *source_str = source.c_str();
+
+               *kernel_program = clCreateProgramWithSource(cxContext, 1, 
&source_str, &source_len, &ciErr);
+
+               if (opencl_error(ciErr))
+                       return false;
+
+               double starttime = time_dt();
+               printf("Compiling OpenCL kernel ...\n");
+
+               if (!build_kernel(kernel_path, kernel_program, 
custom_kernel_build_options, debug_src))
+                       return false;
+
+               printf("Kernel compilation finished in %.2lfs.\n", time_dt() - 
starttime);
+
+               return true;
+       }
+
+
+       bool load_kernels(bool /*experimental*/)
+       {
+               /* verify if device was initialized */
+               if (!device_initialized) {
+                       fprintf(stderr, "OpenCL: failed to initialize 
device.\n");
+                       return false;
+               }
+
+               /* try to use cached kernel */
+               thread_scoped_lock cache_locker;
+               cpProgram = OpenCLCache::get_program(cpPlatform, cdDevice, 
"ocl_dev_base_program", cache_locker);
+
+               if (!cpProgram) {
+                       /* verify we have right opencl version */
+                       if (!opencl_version_check())
+                               return false;
+
+                       /* md5 hash to detect changes */
+                       string kernel_path = path_get("kernel");
+                       string kernel_md5 = path_files_md5_hash(kernel_path);
+                       string custom_kernel_build_options = "";
+                       string device_md5 = 
device_md5_hash(custom_kernel_build_options);
+
+                       /* path to cached binary */
+                       string clbin = 
string_printf("cycles_kernel_%s_%s.clbin", device_md5.c_str(), 
kernel_md5.c_str());
+                       clbin = path_user_get(path_join("cache", clbin));
+
+                       /* path to preprocessed source for debugging */
+                       string clsrc, *debug_src = NULL;
+
+                       if (opencl_kernel_use_debug()) {
+                               clsrc = string_printf("cycles_kernel_%s_%s.cl", 
device_md5.c_str(), kernel_md5.c_str());
+                               clsrc = path_user_get(path_join("cache", 
clsrc));
+                               debug_src = &clsrc;
+                       }
+
+                       /* if exists already, try use it */
+                       if (path_exists(clbin) && load_binary(&cpProgram, 
kernel_path, clbin, custom_kernel_build_options, debug_src)) {
+                               /* kernel loaded from binary */
+                       }
+                       else {
+
+                               string init_kernel_source = "#include 
\"kernel.cl\" // " + kernel_md5 + "\n";
+
+                               /* if does not exist or loading binary failed, 
compile kernel */
+                               if (!compile_kernel(kernel_path, "", 
init_kernel_source, &cpProgram, custom_kernel_build_options, debug_src))
+                                       return false;
+
+                               /* save binary for reuse */
+                               if (!save_binary(&cpProgram, clbin))
+                                       return false;
+                       }
+
+                       /* cache the program */
+                       OpenCLCache::store_program(cpPlatform, cdDevice, 
cpProgram, "ocl_dev_base_program", cache_locker);
+               }
+
+               /* find kernels */
+               ckShaderKernel = clCreateKernel(cpProgram, "kernel_ocl_shader", 
&ciErr);
+               if (opencl_error(ciErr))
+                       return false;
+
+               ckBakeKernel = clCreateKernel(cpProgram, "kernel_ocl_bake", 
&ciErr);
+               if (opencl_error(ciErr))
+                       return false;
+
+               ckFilmConvertByteKernel = clCreateKernel(cpProgram, 
"kernel_ocl_convert_to_byte", &ciErr);
+               if (opencl_error(ciErr))
+                       return false;
+
+               ckFilmConvertHalfFloatKernel = clCreateKernel(cpProgram, 
"kernel_ocl_convert_to_half_float", &ciErr);
+               if (opencl_error(ciErr))
+                       return false;
+
+               retu

@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to