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 */
 };

_______________________________________________
Bf-blender-cvs mailing list
Bf-blender-cvs@blender.org
https://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to