[Bf-blender-cvs] [7f4479d] master: Cycles: OpenCL kernel split

George Kyriazis noreply at git.blender.org
Sat May 9 16:57:48 CEST 2015


Commit: 7f4479da425b2d44a585f1b7b63f91d9dfecef02
Author: George Kyriazis
Date:   Sat May 9 19:34:30 2015 +0500
Branches: master
https://developer.blender.org/rB7f4479da425b2d44a585f1b7b63f91d9dfecef02

Cycles: OpenCL kernel split

This commit contains all the work related on the AMD megakernel split work
which was mainly done by Varun Sundar, George Kyriazis and Lenny Wang, plus
some help from Sergey Sharybin, Martijn Berger, Thomas Dinges and likely
someone else which we're forgetting to mention.

Currently only AMD cards are enabled for the new split kernel, but it is
possible to force split opencl kernel to be used by setting the following
environment variable: CYCLES_OPENCL_SPLIT_KERNEL_TEST=1.

Not all the features are supported yet, and that being said no motion blur,
camera blur, SSS and volumetrics for now. Also transparent shadows are
disabled on AMD device because of some compiler bug.

This kernel is also only implements regular path tracing and supporting
branched one will take a bit. Branched path tracing is exposed to the
interface still, which is a bit misleading and will be hidden there soon.

More feature will be enabled once they're ported to the split kernel and
tested.

Neither regular CPU nor CUDA has any difference, they're generating the
same exact code, which means no regressions/improvements there.

Based on the research paper:

  https://research.nvidia.com/sites/default/files/publications/laine2013hpg_paper.pdf

Here's the documentation:

  https://docs.google.com/document/d/1LuXW-CV-sVJkQaEGZlMJ86jZ8FmoPfecaMdR-oiWbUY/edit

Design discussion of the patch:

  https://developer.blender.org/T44197

Differential Revision: https://developer.blender.org/D1200

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

M	intern/cycles/device/device.h
M	intern/cycles/device/device_opencl.cpp
M	intern/cycles/kernel/CMakeLists.txt
M	intern/cycles/kernel/closure/bsdf.h
M	intern/cycles/kernel/geom/geom_attribute.h
M	intern/cycles/kernel/geom/geom_bvh.h
M	intern/cycles/kernel/geom/geom_motion_triangle.h
M	intern/cycles/kernel/geom/geom_object.h
M	intern/cycles/kernel/geom/geom_primitive.h
M	intern/cycles/kernel/geom/geom_triangle.h
M	intern/cycles/kernel/kernel.cl
M	intern/cycles/kernel/kernel_accumulate.h
A	intern/cycles/kernel/kernel_background_buffer_update.cl
M	intern/cycles/kernel/kernel_camera.h
M	intern/cycles/kernel/kernel_compat_cpu.h
M	intern/cycles/kernel/kernel_compat_cuda.h
M	intern/cycles/kernel/kernel_compat_opencl.h
A	intern/cycles/kernel/kernel_data_init.cl
M	intern/cycles/kernel/kernel_debug.h
M	intern/cycles/kernel/kernel_differential.h
A	intern/cycles/kernel/kernel_direct_lighting.cl
M	intern/cycles/kernel/kernel_emission.h
M	intern/cycles/kernel/kernel_globals.h
A	intern/cycles/kernel/kernel_holdout_emission_blurring_pathtermination_ao.cl
A	intern/cycles/kernel/kernel_lamp_emission.cl
A	intern/cycles/kernel/kernel_next_iteration_setup.cl
M	intern/cycles/kernel/kernel_passes.h
M	intern/cycles/kernel/kernel_path.h
A	intern/cycles/kernel/kernel_path_common.h
M	intern/cycles/kernel/kernel_path_state.h
M	intern/cycles/kernel/kernel_path_surface.h
A	intern/cycles/kernel/kernel_queue_enqueue.cl
A	intern/cycles/kernel/kernel_queues.h
M	intern/cycles/kernel/kernel_random.h
A	intern/cycles/kernel/kernel_scene_intersect.cl
M	intern/cycles/kernel/kernel_shader.h
A	intern/cycles/kernel/kernel_shader_eval.cl
A	intern/cycles/kernel/kernel_shaderdata_vars.h
M	intern/cycles/kernel/kernel_shadow.h
A	intern/cycles/kernel/kernel_shadow_blocked.cl
A	intern/cycles/kernel/kernel_split.h
A	intern/cycles/kernel/kernel_sum_all_radiance.cl
M	intern/cycles/kernel/kernel_types.h
A	intern/cycles/kernel/kernel_work_stealing.h
M	intern/cycles/kernel/svm/svm.h
M	intern/cycles/kernel/svm/svm_attribute.h
M	intern/cycles/kernel/svm/svm_camera.h
M	intern/cycles/kernel/svm/svm_closure.h
M	intern/cycles/kernel/svm/svm_displace.h
M	intern/cycles/kernel/svm/svm_fresnel.h
M	intern/cycles/kernel/svm/svm_geometry.h
M	intern/cycles/kernel/svm/svm_image.h
M	intern/cycles/kernel/svm/svm_light_path.h
M	intern/cycles/kernel/svm/svm_tex_coord.h
M	intern/cycles/kernel/svm/svm_vector_transform.h
M	intern/cycles/kernel/svm/svm_wireframe.h
M	intern/cycles/render/session.cpp

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

diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h
index 4d40518..162f512 100644
--- a/intern/cycles/device/device.h
+++ b/intern/cycles/device/device.h
@@ -55,6 +55,7 @@ public:
 	bool advanced_shading;
 	bool pack_images;
 	bool extended_images; /* flag for GPU and Multi device */
+	bool use_split_kernel; /* Denotes if the device is going to run cycles using split-kernel */
 	vector<DeviceInfo> multi_devices;
 
 	DeviceInfo()
@@ -66,6 +67,7 @@ public:
 		advanced_shading = true;
 		pack_images = false;
 		extended_images = false;
+		use_split_kernel = false;
 	}
 };
 
diff --git a/intern/cycles/device/device_opencl.cpp b/intern/cycles/device/device_opencl.cpp
index 1147cbd..25eb160 100644
--- a/intern/cycles/device/device_opencl.cpp
+++ b/intern/cycles/device/device_opencl.cpp
@@ -39,6 +39,30 @@
 CCL_NAMESPACE_BEGIN
 
 #define CL_MEM_PTR(p) ((cl_mem)(uintptr_t)(p))
+#define KERNEL_APPEND_ARG(kernel_name, arg) \
+               opencl_assert(clSetKernelArg(kernel_name, narg++, sizeof(arg), (void*)&arg))
+
+/* Macro declarations used with split kernel */
+
+/* Macro to enable/disable work-stealing */
+#define __WORK_STEALING__
+
+#define SPLIT_KERNEL_LOCAL_SIZE_X 64
+#define SPLIT_KERNEL_LOCAL_SIZE_Y 1
+
+/* This value may be tuned according to the scene we are rendering.
+ *
+ * Modifying PATH_ITER_INC_FACTOR value proportional to number of expected
+ * ray-bounces will improve performance.
+ */
+#define PATH_ITER_INC_FACTOR 8
+
+/* When allocate global memory in chunks. We may not be able to
+ * allocate exactly "CL_DEVICE_MAX_MEM_ALLOC_SIZE" bytes in chunks;
+ * Since some bytes may be needed for aligning chunks of memory;
+ * This is the amount of memory that we dedicate for that purpose.
+ */
+#define DATA_ALLOCATION_MEM_FACTOR 5000000 //5MB
 
 static cl_device_type opencl_device_type()
 {
@@ -94,11 +118,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())
@@ -118,14 +142,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);
@@ -236,6 +264,12 @@ class OpenCLCache
 	}
 
 public:
+
+	enum ProgramName {
+		OCL_DEV_BASE_PROGRAM,
+		OCL_DEV_MEGAKERNEL_PROGRAM,
+	};
+
 	/* see get_something comment */
 	static cl_context get_context(cl_platform_id platform, cl_device_id device,
 		thread_scoped_lock &slot_locker)
@@ -254,10 +288,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, ProgramName 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 {
+			assert(!"Invalid program name");
+		}
 
 		if(!program)
 			return NULL;
@@ -284,10 +329,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, ProgramName 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 {
+			assert(!"Invalid program name\n");
+			return;
+		}
 
 		/* increment reference count in OpenCL.
 		 * The caller is going to release the object when done with it. */
@@ -304,8 +357,10 @@ 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.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);
 		}
@@ -314,7 +369,7 @@ public:
 	}
 };
 
-class OpenCLDevice : public Device
+class OpenCLDeviceBase : public Device
 {
 public:
 	DedicatedTaskPool task_pool;
@@ -323,7 +378,6 @@ public:
 	cl_platform_id cpPlatform;
 	cl_device_id cdDevice;
 	cl_program cpProgram;
-	cl_kernel ckPathTraceKernel;
 	cl_kernel ckFilmConvertByteKernel;
 	cl_kernel ckFilmConvertHalfFloatKernel;
 	cl_kernel ckShaderKernel;
@@ -385,7 +439,7 @@ public:
 		}
 	}
 
-	OpenCLDevice(DeviceInfo& info, Stats &stats, bool background_)
+	OpenCLDeviceBase(DeviceInfo& info, Stats &stats, bool background_)
 	: Device(info, stats, background_)
 	{
 		cpPlatform = NULL;
@@ -393,7 +447,6 @@ public:
 		cxContext = NULL;
 		cqCommandQueue = NULL;
 		cpProgram = NULL;
-		ckPathTraceKernel = NULL;
 		ckFilmConvertByteKernel = NULL;
 		ckFilmConvertHalfFloatKernel = NULL;
 		ckShaderKernel = NULL;
@@ -501,7 +554,7 @@ public:
 		if(opencl_error(ciErr))
 			return;
 
-		fprintf(stderr,"Device init succes\n");
+		fprintf(stderr, "Device init success\n");
 		device_initialized = true;
 	}
 
@@ -547,7 +600,11 @@ public:
 		return true;
 	}
 
-	bool load_binary(const string& kernel_path, const string& clbin, const string *debug_src = NULL)
+	bool load_binary(const string& /*kernel_path*/,
+	                 const string& clbin,
+	                 string custom_kernel_build_options,
+	                 cl_program *program,
+	                 const string *debug_src = NULL)
 	{
 		/* read binary into memory */
 		vector<uint8_t> binary;
@@ -562,7 +619,7 @@ public:
 		size_t size = binary.size();
 		const uint8_t *bytes = &binary[0];
 
-		cpProgram = clCreateProgramWithBinary(cxContext, 1, &cdDevice,
+		*program = clCreateProgramWithBinary(cxContext, 1, &cdDevice,
 			&size, &bytes, &status, &ciErr);
 
 		if(opencl_error(status) || opencl_error(ciErr)) {
@@ -570,16 +627,16 @@ public:
 			return false;
 		}
 
-		if(!build_kernel(kernel_path, debug_src))
+		if(!build_kernel(program, custom_kernel_build_options, debug_src))
 			return false;
 
 		return true;
 	}
 
-	bool save_binary(const string& clbin)
+	bool save_binary(cl_program *program, const string& clbin)
 	{
 		size_t size = 0;
-		clGetProgramInfo(cpProgram, CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &size, NULL);
+		clGetProgramInfo(*program, CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &size, NULL);
 
 		if(!size)
 			return false;
@@ -587,7 +644,7 @@ public:
 		vector<uint8_t> binary(size);
 		uint8_t *bytes = &binary[0];
 
-		clGetProgramInfo(cpProgram, CL_PROGRAM_BINARIES, sizeof(uint8_t*), &bytes, NULL);
+		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()));
@@ -597,20 +654,23 @@ public:
 		return true;
 	}
 
-	bool build_kernel(const string& /*kernel_path*/, const string *debug_src = NULL)
+	bool build_kernel(cl_program *kernel_program,
+	                  string custom_kernel_build_options,
+	                  const string *debug_src = NULL)
 	{
-		string build_options = opencl_kernel_build_options(platform_name, debug_src);
-	
-		ciErr = clBuildProgram(cpProgram, 0, NULL, build_options.c_str(), NULL, 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(cpProgram, cdDevice, CL_PROGRAM_BUILD_LOG, 0, NULL, &ret_val_size);
+		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(cpProgram, cdDevice, CL_PROGRAM_BUILD_LOG, ret_val_size, &build_log[0], NULL);
+			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");
@@ -625,12 +685,15 @@ public:
 		return true;
 	}
 
-	bool compile_kernel(const string& kernel_path, const string& kernel_md5, const string *debug_src = NULL)
+	bool compile_kernel(con

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list