[Bf-blender-cvs] [2f6257fd7fe] blender2.7: Cycles/OpenCL: Compile Kernels During Scene Update

Jeroen Bakker noreply at git.blender.org
Fri Mar 15 16:22:08 CET 2019


Commit: 2f6257fd7fe305e3b226a8b505eb614bbeaf762a
Author: Jeroen Bakker
Date:   Wed Mar 13 12:31:48 2019 +0100
Branches: blender2.7
https://developer.blender.org/rB2f6257fd7fe305e3b226a8b505eb614bbeaf762a

Cycles/OpenCL: Compile Kernels During Scene Update

The main goals of this change is faster starting when using foreground
rendering.

This patch will build kernels in parallel to the update process of
the scene. When these optimized kernels are not available (yet) an AO
kernel will be used.

These AO kernels are fast to compile (3-7 seconds) and can be
reused by all scenes. When the final kernels become available we
will switch to these kernels.

In background mode the AO kernels will not be used.
Some kernels are being used during Scene update (displace, background
light). When these kernels are being used the process can halt until
these become available.

Reviewed By: brecht, #cycles

Maniphest Tasks: T61752

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

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

M	intern/cycles/blender/blender_session.cpp
M	intern/cycles/blender/blender_session.h
M	intern/cycles/device/device.h
M	intern/cycles/device/device_multi.cpp
M	intern/cycles/device/opencl/opencl.h
M	intern/cycles/device/opencl/opencl_split.cpp
M	intern/cycles/device/opencl/opencl_util.cpp
M	intern/cycles/kernel/kernel_types.h
M	intern/cycles/render/session.cpp
M	intern/cycles/render/session.h
M	intern/cycles/util/util_progress.h
M	intern/cycles/util/util_task.cpp
M	intern/cycles/util/util_task.h

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

diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp
index ab08b9e146d..27541800804 100644
--- a/intern/cycles/blender/blender_session.cpp
+++ b/intern/cycles/blender/blender_session.cpp
@@ -933,6 +933,11 @@ void BlenderSession::get_status(string& status, string& substatus)
 	session->progress.get_status(status, substatus);
 }
 
+void BlenderSession::get_kernel_status(string& kernel_status)
+{
+	session->progress.get_kernel_status(kernel_status);
+}
+
 void BlenderSession::get_progress(float& progress, double& total_time, double& render_time)
 {
 	session->progress.get_time(total_time, render_time);
@@ -951,7 +956,7 @@ void BlenderSession::update_bake_progress()
 
 void BlenderSession::update_status_progress()
 {
-	string timestatus, status, substatus;
+	string timestatus, status, substatus, kernel_status;
 	string scene = "";
 	float progress;
 	double total_time, remaining_time = 0, render_time;
@@ -960,6 +965,7 @@ void BlenderSession::update_status_progress()
 	float mem_peak = (float)session->stats.mem_peak / 1024.0f / 1024.0f;
 
 	get_status(status, substatus);
+	get_kernel_status(kernel_status);
 	get_progress(progress, total_time, render_time);
 
 	if(progress > 0)
@@ -989,6 +995,8 @@ void BlenderSession::update_status_progress()
 		status = " | " + status;
 	if(substatus.size() > 0)
 		status += " | " + substatus;
+	if(kernel_status.size() > 0)
+		status += " | " + kernel_status;
 
 	double current_time = time_dt();
 	/* When rendering in a window, redraw the status at least once per second to keep the elapsed and remaining time up-to-date.
diff --git a/intern/cycles/blender/blender_session.h b/intern/cycles/blender/blender_session.h
index 2aa3c77c37d..2c0a83cf6e7 100644
--- a/intern/cycles/blender/blender_session.h
+++ b/intern/cycles/blender/blender_session.h
@@ -90,6 +90,7 @@ public:
 	void tag_redraw();
 	void tag_update();
 	void get_status(string& status, string& substatus);
+	void get_kernel_status(string& kernel_status);
 	void get_progress(float& progress, double& total_time, double& render_time);
 	void test_cancel();
 	void update_status_progress();
diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h
index 3bf978600d5..6f3208e955f 100644
--- a/intern/cycles/device/device.h
+++ b/intern/cycles/device/device.h
@@ -56,6 +56,14 @@ enum DeviceTypeMask {
 	DEVICE_MASK_ALL = ~0
 };
 
+enum DeviceKernelStatus {
+	DEVICE_KERNEL_WAITING_FOR_FEATURE_KERNEL = 0,
+	DEVICE_KERNEL_FEATURE_KERNEL_AVAILABLE,
+	DEVICE_KERNEL_USING_FEATURE_KERNEL,
+	DEVICE_KERNEL_FEATURE_KERNEL_INVALID,
+	DEVICE_KERNEL_UNKNOWN,
+};
+
 #define DEVICE_MASK(type) (DeviceTypeMask)(1 << type)
 
 class DeviceInfo {
@@ -321,6 +329,20 @@ public:
 	        const DeviceRequestedFeatures& /*requested_features*/)
 	{ return true; }
 
+	/* Wait for device to become available to upload data and receive tasks
+	 * This method is used by the OpenCL device to load the
+	 * optimized kernels or when not (yet) available load the
+	 * generic kernels (only during foreground rendering) */
+	virtual bool wait_for_availability(
+	        const DeviceRequestedFeatures& /*requested_features*/)
+	{ return true; }
+	/* Check if there are 'better' kernels available to be used
+	 * We can switch over to these kernels
+	 * This method is used to determine if we can switch the preview kernels
+	 * to regular kernels */
+	virtual DeviceKernelStatus get_active_kernel_switch_state()
+	{ return DEVICE_KERNEL_USING_FEATURE_KERNEL; }
+
 	/* tasks */
 	virtual int get_split_task_count(DeviceTask& task) = 0;
 	virtual void task_add(DeviceTask& task) = 0;
diff --git a/intern/cycles/device/device_multi.cpp b/intern/cycles/device/device_multi.cpp
index 2fac4fa071b..516b86654aa 100644
--- a/intern/cycles/device/device_multi.cpp
+++ b/intern/cycles/device/device_multi.cpp
@@ -120,6 +120,37 @@ public:
 		return true;
 	}
 
+	bool wait_for_availability(const DeviceRequestedFeatures& requested_features)
+	{
+		foreach(SubDevice& sub, devices)
+			if(!sub.device->wait_for_availability(requested_features))
+				return false;
+
+		return true;
+	}
+
+	DeviceKernelStatus get_active_kernel_switch_state()
+	{
+		DeviceKernelStatus result = DEVICE_KERNEL_USING_FEATURE_KERNEL;
+
+		foreach(SubDevice& sub, devices) {
+			DeviceKernelStatus subresult = sub.device->get_active_kernel_switch_state();
+			switch (subresult) {
+				case DEVICE_KERNEL_WAITING_FOR_FEATURE_KERNEL:
+					result = subresult;
+					break;
+
+				case DEVICE_KERNEL_FEATURE_KERNEL_INVALID:
+				case DEVICE_KERNEL_FEATURE_KERNEL_AVAILABLE:
+					return subresult;
+
+				case DEVICE_KERNEL_USING_FEATURE_KERNEL:
+					break;
+			}
+		}
+		return result;
+	}
+
 	void mem_alloc(device_memory& mem)
 	{
 		device_ptr key = unique_key++;
diff --git a/intern/cycles/device/opencl/opencl.h b/intern/cycles/device/opencl/opencl.h
index 2a4e07419ac..bb507be4c72 100644
--- a/intern/cycles/device/opencl/opencl.h
+++ b/intern/cycles/device/opencl/opencl.h
@@ -261,16 +261,22 @@ class OpenCLDevice : public Device
 {
 public:
 	DedicatedTaskPool task_pool;
+
+	/* Task pool for required kernels (base, AO kernels during foreground rendering) */
+	TaskPool load_required_kernel_task_pool;
+	/* Task pool for optional kernels (feature kernels during foreground rendering) */
+	TaskPool load_kernel_task_pool;
 	cl_context cxContext;
 	cl_command_queue cqCommandQueue;
 	cl_platform_id cpPlatform;
 	cl_device_id cdDevice;
 	cl_int ciErr;
 	int device_num;
+	bool use_preview_kernels;
 
 	class OpenCLProgram {
 	public:
-		OpenCLProgram() : loaded(false), program(NULL), device(NULL) {}
+		OpenCLProgram() : loaded(false), needs_compiling(true), program(NULL), device(NULL) {}
 		OpenCLProgram(OpenCLDevice *device,
 		              const string& program_name,
 		              const string& kernel_name,
@@ -279,12 +285,24 @@ public:
 		~OpenCLProgram();
 
 		void add_kernel(ustring name);
-		void load();
+
+		/* Try to load the program from device cache or disk */
+		bool load();
+		/* Compile the kernel (first separate, failback to local) */
+		void compile();
+		/* Create the OpenCL kernels after loading or compiling */
+		void create_kernels();
 
 		bool is_loaded() const { return loaded; }
 		const string& get_log() const { return log; }
 		void report_error();
 
+		/* Wait until this kernel is available to be used 
+		 * It will return true when the kernel is available.
+		 * It will return false when the kernel is not available 
+		 * or could not be loaded. */
+		bool wait_for_availability();
+
 		cl_kernel operator()();
 		cl_kernel operator()(ustring name);
 
@@ -308,6 +326,8 @@ public:
 		void add_error(const string& msg);
 
 		bool loaded;
+		bool needs_compiling;
+
 		cl_program program;
 		OpenCLDevice *device;
 
@@ -323,19 +343,32 @@ public:
 		map<ustring, cl_kernel> kernels;
 	};
 
-	DeviceSplitKernel *split_kernel;
-
-	OpenCLProgram program_split;
+	/* Container for all types of split programs. */
+	class OpenCLSplitPrograms {
+		public:
+			OpenCLDevice *device;
+			OpenCLProgram program_split;
+			OpenCLProgram program_lamp_emission;
+			OpenCLProgram program_do_volume;
+			OpenCLProgram program_indirect_background;
+			OpenCLProgram program_shader_eval;
+			OpenCLProgram program_holdout_emission_blurring_pathtermination_ao;
+			OpenCLProgram program_subsurface_scatter;
+			OpenCLProgram program_direct_lighting;
+			OpenCLProgram program_shadow_blocked_ao;
+			OpenCLProgram program_shadow_blocked_dl;
+
+			OpenCLSplitPrograms(OpenCLDevice *device);
+			~OpenCLSplitPrograms();
+
+			/* Load the kernels and put the created kernels in the given `programs`
+			 * paramter. */
+			void load_kernels(vector<OpenCLProgram*> &programs,
+			                  const DeviceRequestedFeatures& requested_features,
+			                  bool is_preview=false);
+	};
 
-	OpenCLProgram program_lamp_emission;
-	OpenCLProgram program_do_volume;
-	OpenCLProgram program_indirect_background;
-	OpenCLProgram program_shader_eval;
-	OpenCLProgram program_holdout_emission_blurring_pathtermination_ao;
-	OpenCLProgram program_subsurface_scatter;
-	OpenCLProgram program_direct_lighting;
-	OpenCLProgram program_shadow_blocked_ao;
-	OpenCLProgram program_shadow_blocked_dl;
+	DeviceSplitKernel *split_kernel;
 
 	OpenCLProgram base_program;
 	OpenCLProgram bake_program;
@@ -343,6 +376,9 @@ public:
 	OpenCLProgram background_program;
 	OpenCLProgram denoising_program;
 
+	OpenCLSplitPrograms kernel_programs;
+	OpenCLSplitPrograms preview_programs;
+
 	typedef map<string, device_vector<uchar>*> ConstMemMap;
 	typedef map<string, device_ptr> MemMap;
 
@@ -358,22 +394,30 @@ public:
 	void opencl_error(const string& message);
 	void opencl_assert_err(cl_int err, const char* where);
 
-	OpenCLDevice(DeviceInfo& info, Stats &stats, Profiler &profiler, bool background_);
+	OpenCLDevice(DeviceInfo& info, Stats &stats, Profiler &profiler, bool background);
 	~OpenCLDevice();
 
 	static void CL_CALLBACK context_notify_callback(const char *err_info,
 		const void * /*private_info*/, size_t /*cb*/, void *user_data);
 
 	bool opencl_version_check();
+	OpenCLSplitPrograms* get_split_programs();
 
 	string device_md5_hash(string kernel_custom_build_options = "");
 	bool load_kernels(const DeviceRequestedFeatures& requested_features);
+	void load_required_kernels(const DeviceRequestedFeatures& requested_features);
+	void load_preview_kernels();
+
+	bool wait_for_availability(const DeviceRequestedFeatures& requested_features);
+	DeviceKernelStatus get_active_kernel_switch_state();
 
 	/* Get the name of the opencl program for the given kernel */
 	const string get_opencl_program_name(const string& kernel_name);
 	/* Get the program file name to compile (*.cl) for the given kernel */
 	const string get_opencl_program_filename(const string& kernel_name);
-	string get_build_options(const DeviceRequestedFeatures& requested_features, const string& opencl_program_name);
+	string get_build_options(const DeviceRequestedFeatures& requested_features,
+	                         const string& opencl_program_name,
+	                         bool preview_kernel=false);
 	/* Enable the default features to reduce recompilation events */
 	void enable_default_featu

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list