[Bf-blender-cvs] [94fadd00d88] blender2.8: DRW: Shader Deferred compilation: Use a wmJob for threading.

Clément Foucault noreply at git.blender.org
Tue Mar 6 16:45:38 CET 2018


Commit: 94fadd00d889254ea59ca97c85a32ca76b9e95ca
Author: Clément Foucault
Date:   Mon Mar 5 21:50:56 2018 +0100
Branches: blender2.8
https://developer.blender.org/rB94fadd00d889254ea59ca97c85a32ca76b9e95ca

DRW: Shader Deferred compilation: Use a wmJob for threading.

Also get rid of the static var and initialization.
This enables the user to see the progress on the info header.
Closing blender or reading a file also kill the job which is good.

Unfortunatly, this job cannot be interrupt by users directly. We could make it interruptible but we need a way to resume the compilation.

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

M	source/blender/draw/intern/draw_manager.c
M	source/blender/draw/intern/draw_manager.h
M	source/blender/draw/intern/draw_manager_shader.c
M	source/blender/windowmanager/WM_api.h

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

diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index ac39bbf132a..8feffa246ef 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -1957,7 +1957,6 @@ void DRW_opengl_context_create(void)
 
 	immDeactivate();
 	/* This changes the active context. */
-	DRW_deferred_compiler_init();
 	DST.ogl_context = WM_opengl_context_create();
 	/* Be sure to create gawain.context too. */
 	DST.gwn_context = GWN_context_create();
@@ -1972,7 +1971,6 @@ void DRW_opengl_context_destroy(void)
 {
 	BLI_assert(BLI_thread_is_main());
 	if (DST.ogl_context != NULL) {
-		DRW_deferred_compiler_exit();
 		WM_opengl_context_activate(DST.ogl_context);
 		GWN_context_active_set(DST.gwn_context);
 		GWN_context_discard(DST.gwn_context);
diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h
index 3c6682050cf..f8989a0703a 100644
--- a/source/blender/draw/intern/draw_manager.h
+++ b/source/blender/draw/intern/draw_manager.h
@@ -356,7 +356,4 @@ void *drw_viewport_engine_data_ensure(void *engine_type);
 
 void drw_state_set(DRWState state);
 
-void DRW_deferred_compiler_init(void);
-void DRW_deferred_compiler_exit(void);
-
 #endif /* __DRAW_MANAGER_H__ */
diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c
index 27605012993..0e96c726999 100644
--- a/source/blender/draw/intern/draw_manager_shader.c
+++ b/source/blender/draw/intern/draw_manager_shader.c
@@ -34,10 +34,14 @@
 #include "BLI_threads.h"
 #include "BLI_task.h"
 
+#include "BKE_global.h"
+#include "BKE_main.h"
+
 #include "GPU_shader.h"
 #include "GPU_material.h"
 
 #include "WM_api.h"
+#include "WM_types.h"
 
 extern char datatoc_gpu_shader_2D_vert_glsl[];
 extern char datatoc_gpu_shader_3D_vert_glsl[];
@@ -58,30 +62,21 @@ typedef struct DRWDeferredShader {
 
 	GPUMaterial *mat;
 	char *vert, *geom, *frag, *defs;
-
-	ThreadMutex compilation_mutex;
 } DRWDeferredShader;
 
 typedef struct DRWShaderCompiler {
 	ListBase queue; /* DRWDeferredShader */
-	ThreadMutex list_mutex;
+	SpinLock list_lock;
 
 	DRWDeferredShader *mat_compiling;
-	ThreadMutex compilation_mutex;
-
-	TaskScheduler *task_scheduler; /* NULL if nothing is running. */
-	TaskPool *task_pool;
+	ThreadMutex compilation_lock;
 
-	void *ogl_context;
+	int shaders_done; /* To compute progress. */
 } DRWShaderCompiler;
 
-static DRWShaderCompiler DSC = {{NULL}};
-
 static void drw_deferred_shader_free(DRWDeferredShader *dsh)
 {
 	/* Make sure it is not queued before freeing. */
-	BLI_assert(BLI_findindex(&DSC.queue, dsh) == -1);
-
 	MEM_SAFE_FREE(dsh->vert);
 	MEM_SAFE_FREE(dsh->geom);
 	MEM_SAFE_FREE(dsh->frag);
@@ -90,34 +85,77 @@ static void drw_deferred_shader_free(DRWDeferredShader *dsh)
 	MEM_freeN(dsh);
 }
 
-static void drw_deferred_shader_compilation_exec(TaskPool * __restrict UNUSED(pool), void *UNUSED(taskdata), int UNUSED(threadid))
+static void drw_deferred_shader_queue_free(ListBase *queue)
 {
-	WM_opengl_context_activate(DSC.ogl_context);
+	DRWDeferredShader *dsh;
+	while((dsh = BLI_pophead(queue))) {
+		drw_deferred_shader_free(dsh);
+	}
+}
+
+static void drw_deferred_shader_compilation_exec(void *custom_data, short *stop, short *do_update, float *progress)
+{
+	DRWShaderCompiler *comp = (DRWShaderCompiler *)custom_data;
+
+	/* Create one context per task. */
+	void *ogl_context = WM_opengl_context_create();
+	WM_opengl_context_activate(ogl_context);
 
 	while (true) {
-		BLI_mutex_lock(&DSC.list_mutex);
-		DSC.mat_compiling = BLI_pophead(&DSC.queue);
-		if (DSC.mat_compiling == NULL) {
+		BLI_spin_lock(&comp->list_lock);
+
+		if (*stop != 0) {
+			/* We don't want user to be able to cancel the compilation
+			 * but wm can kill the task if we are closing blender. */
+			BLI_spin_unlock(&comp->list_lock);
 			break;
 		}
-		BLI_mutex_lock(&DSC.compilation_mutex);
-		BLI_mutex_unlock(&DSC.list_mutex);
+
+		/* Pop tail because it will be less likely to lock the main thread
+		 * if all GPUMaterials are to be freed (see DRW_deferred_shader_remove()). */
+		comp->mat_compiling = BLI_poptail(&comp->queue);
+		if (comp->mat_compiling == NULL) {
+			/* No more Shader to compile. */
+			BLI_spin_unlock(&comp->list_lock);
+			break;
+		}
+
+		comp->shaders_done++;
+		int total = BLI_listbase_count(&comp->queue) + comp->shaders_done;
+
+		BLI_mutex_lock(&comp->compilation_lock);
+		BLI_spin_unlock(&comp->list_lock);
 
 		/* Do the compilation. */
 		GPU_material_generate_pass(
-		        DSC.mat_compiling->mat,
-		        DSC.mat_compiling->vert,
-		        DSC.mat_compiling->geom,
-		        DSC.mat_compiling->frag,
-		        DSC.mat_compiling->defs);
+		        comp->mat_compiling->mat,
+		        comp->mat_compiling->vert,
+		        comp->mat_compiling->geom,
+		        comp->mat_compiling->frag,
+		        comp->mat_compiling->defs);
+
+		*progress = (float)comp->shaders_done / (float)total;
+		*do_update = true;
 
-		BLI_mutex_unlock(&DSC.compilation_mutex);
+		BLI_mutex_unlock(&comp->compilation_lock);
 
-		drw_deferred_shader_free(DSC.mat_compiling);
+		drw_deferred_shader_free(comp->mat_compiling);
 	}
 
-	WM_opengl_context_release(DSC.ogl_context);
-	BLI_mutex_unlock(&DSC.list_mutex);
+	WM_opengl_context_release(ogl_context);
+	WM_opengl_context_dispose(ogl_context);
+}
+
+static void drw_deferred_shader_compilation_free(void *custom_data)
+{
+	DRWShaderCompiler *comp = (DRWShaderCompiler *)custom_data;
+
+	drw_deferred_shader_queue_free(&comp->queue);
+
+	BLI_spin_end(&comp->list_lock);
+	BLI_mutex_end(&comp->compilation_lock);
+
+	MEM_freeN(comp);
 }
 
 static void drw_deferred_shader_add(
@@ -137,63 +175,68 @@ static void drw_deferred_shader_add(
 	if (frag_lib) dsh->frag = BLI_strdup(frag_lib);
 	if (defines)  dsh->defs = BLI_strdup(defines);
 
-	BLI_mutex_lock(&DSC.list_mutex);
-	BLI_addtail(&DSC.queue, dsh);
-	if (DSC.mat_compiling == NULL) {
-		/* Set value so that other threads do not start a new task. */
-		DSC.mat_compiling = (void *)1;
+	BLI_assert(DST.draw_ctx.evil_C);
+	wmWindowManager *wm = CTX_wm_manager(DST.draw_ctx.evil_C);
+	wmWindow *win = CTX_wm_window(DST.draw_ctx.evil_C);
+	Scene *scene = DST.draw_ctx.scene;
 
-		if (DSC.task_scheduler == NULL) {
-			DSC.task_scheduler = BLI_task_scheduler_create(1);
-			DSC.task_pool = BLI_task_pool_create_background(DSC.task_scheduler, NULL);
-		}
-		BLI_task_pool_push(DSC.task_pool, drw_deferred_shader_compilation_exec, NULL, false, TASK_PRIORITY_LOW);
-	}
-	BLI_mutex_unlock(&DSC.list_mutex);
-}
+	/* Get the running job or a new one if none is running. Can only have one job per type & owner.  */
+	wmJob *wm_job = WM_jobs_get(wm, win, scene, "Shaders Compilation",
+	                            WM_JOB_PROGRESS | WM_JOB_SUSPEND, WM_JOB_TYPE_SHADER_COMPILATION);
 
-void DRW_deferred_shader_remove(GPUMaterial *mat)
-{
-	BLI_mutex_lock(&DSC.list_mutex);
-	DRWDeferredShader *dsh = (DRWDeferredShader *)BLI_findptr(&DSC.queue, mat, offsetof(DRWDeferredShader, mat));
-	if (dsh) {
-		BLI_remlink(&DSC.queue, dsh);
-	}
-	if (DSC.mat_compiling != NULL) {
-		if (DSC.mat_compiling->mat == mat) {
-			/* Wait for compilation to finish */
-			BLI_mutex_lock(&DSC.compilation_mutex);
-			BLI_mutex_unlock(&DSC.compilation_mutex);
-		}
-	}
-	BLI_mutex_unlock(&DSC.list_mutex);
-	if (dsh) {
-		drw_deferred_shader_free(dsh);
-	}
-}
+	DRWShaderCompiler *old_comp = (DRWShaderCompiler *)WM_jobs_customdata_get(wm_job);
 
+	DRWShaderCompiler *comp = MEM_callocN(sizeof(DRWShaderCompiler), "DRWShaderCompiler");
+	BLI_spin_init(&comp->list_lock);
+	BLI_mutex_init(&comp->compilation_lock);
 
-static void drw_deferred_compiler_finish(void)
-{
-	if (DSC.task_scheduler != NULL) {
-		BLI_task_pool_work_and_wait(DSC.task_pool);
-		BLI_task_pool_free(DSC.task_pool);
-		BLI_task_scheduler_free(DSC.task_scheduler);
-		DSC.task_scheduler = NULL;
+	if (old_comp) {
+		BLI_spin_lock(&old_comp->list_lock);
+		BLI_movelisttolist(&comp->queue, &old_comp->queue);
+		BLI_spin_unlock(&old_comp->list_lock);
 	}
-}
 
-void DRW_deferred_compiler_init(void)
-{
-	BLI_mutex_init(&DSC.list_mutex);
-	BLI_mutex_init(&DSC.compilation_mutex);
-	DSC.ogl_context = WM_opengl_context_create();
+	BLI_addtail(&comp->queue, dsh);
+
+	WM_jobs_customdata_set(wm_job, comp, drw_deferred_shader_compilation_free);
+	WM_jobs_timer(wm_job, 0.1, NC_MATERIAL | ND_SHADING_DRAW, 0);
+	WM_jobs_callbacks(wm_job, drw_deferred_shader_compilation_exec, NULL, NULL, NULL);
+	WM_jobs_start(wm, wm_job);
 }
 
-void DRW_deferred_compiler_exit(void)
+void DRW_deferred_shader_remove(GPUMaterial *mat)
 {
-	drw_deferred_compiler_finish();
-	WM_opengl_context_dispose(DSC.ogl_context);
+	Scene *scene = GPU_material_scene(mat);
+
+	for (wmWindowManager *wm = G.main->wm.first; wm; wm = wm->id.next) {
+		for (wmWindow *win = wm->windows.first; win; win = win->next) {
+			wmJob *wm_job = WM_jobs_get(wm, win, scene, "Shaders Compilation",
+			                            WM_JOB_PROGRESS | WM_JOB_SUSPEND, WM_JOB_TYPE_SHADER_COMPILATION);
+
+			DRWShaderCompiler *comp = (DRWShaderCompiler *)WM_jobs_customdata_get(wm_job);
+			if (comp != NULL) {
+				BLI_spin_lock(&comp->list_lock);
+				DRWDeferredShader *dsh;
+				dsh = (DRWDeferredShader *)BLI_findptr(&comp->queue, mat, offsetof(DRWDeferredShader, mat));
+				if (dsh) {
+					BLI_remlink(&comp->queue, dsh);
+				}
+
+				/* Wait for compilation to finish */
+				if (comp->mat_compiling != NULL) {
+					if (comp->mat_compiling->mat == mat) {
+						BLI_mutex_lock(&comp->compilation_lock);
+						BLI_mutex_unlock(&comp->compilation_lock);
+					}
+				}
+				BLI_spin_unlock(&comp->list_lock);
+
+				if (dsh) {
+					drw_deferred_shader_free(dsh);
+				}
+			}
+		}
+	}
 }
 
 /** \} */
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index bf894b2ad03..742adda2644 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -504,6 +504,7 @@ enum {
 	WM_JOB_TYPE_POINTCACHE,
 	WM_JOB_TYPE_DPAINT_BAKE,
 	WM_JOB_TYPE_ALEMBIC,
+	WM_JOB_TYPE_SHADER_COMPILATION,
 	/* add as needed, screencast, seq proxy build
 	 * if having hard coded values is a problem */
 };



More information about the Bf-blender-cvs mailing list