Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClément Foucault <foucault.clem@gmail.com>2018-03-05 02:54:31 +0300
committerClément Foucault <foucault.clem@gmail.com>2018-03-06 18:44:04 +0300
commit3a209c285754a08339c654d075b5d273fa264c08 (patch)
treebd1121dc7c095af648263e0dbef1b6cf76f7d4e5 /source/blender/draw/intern
parentf14cbc0d0773d33f917c75f84b25dbc1e48a2976 (diff)
DRW: Deferred compilation initial implementation.
Diffstat (limited to 'source/blender/draw/intern')
-rw-r--r--source/blender/draw/intern/DRW_render.h6
-rw-r--r--source/blender/draw/intern/draw_manager.c2
-rw-r--r--source/blender/draw/intern/draw_manager.h3
-rw-r--r--source/blender/draw/intern/draw_manager_shader.c192
4 files changed, 203 insertions, 0 deletions
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index d8885bd77c5..4815c117a8c 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -268,6 +268,12 @@ struct GPUShader *DRW_shader_create_2D(const char *frag, const char *defines);
struct GPUShader *DRW_shader_create_3D(const char *frag, const char *defines);
struct GPUShader *DRW_shader_create_fullscreen(const char *frag, const char *defines);
struct GPUShader *DRW_shader_create_3D_depth_only(void);
+struct GPUMaterial *DRW_shader_create_from_world(
+ struct Scene *scene, struct World *wo, const void *engine_type, int options,
+ const char *vert, const char *geom, const char *frag_lib, const char *defines);
+struct GPUMaterial *DRW_shader_create_from_material(
+ struct Scene *scene, struct Material *ma, const void *engine_type, int options,
+ const char *vert, const char *geom, const char *frag_lib, const char *defines);
void DRW_shader_free(struct GPUShader *shader);
#define DRW_SHADER_FREE_SAFE(shader) do { \
if (shader != NULL) { \
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 8feffa246ef..ac39bbf132a 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -1957,6 +1957,7 @@ 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();
@@ -1971,6 +1972,7 @@ 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 f8989a0703a..3c6682050cf 100644
--- a/source/blender/draw/intern/draw_manager.h
+++ b/source/blender/draw/intern/draw_manager.h
@@ -356,4 +356,7 @@ 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 e9d2ac14e57..27605012993 100644
--- a/source/blender/draw/intern/draw_manager_shader.c
+++ b/source/blender/draw/intern/draw_manager_shader.c
@@ -25,15 +25,181 @@
#include "draw_manager.h"
+#include "DNA_world_types.h"
+#include "DNA_material_types.h"
+
+#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_string_utils.h"
+#include "BLI_threads.h"
+#include "BLI_task.h"
#include "GPU_shader.h"
+#include "GPU_material.h"
+
+#include "WM_api.h"
extern char datatoc_gpu_shader_2D_vert_glsl[];
extern char datatoc_gpu_shader_3D_vert_glsl[];
extern char datatoc_gpu_shader_fullscreen_vert_glsl[];
+
+/* -------------------------------------------------------------------- */
+
+/** \name Deferred Compilation (DRW_deferred)
+ *
+ * Since compiling shader can take a long time, we do it in a non blocking
+ * manner in another thread.
+ *
+ * \{ */
+
+typedef struct DRWDeferredShader {
+ struct DRWDeferredShader *prev, *next;
+
+ GPUMaterial *mat;
+ char *vert, *geom, *frag, *defs;
+
+ ThreadMutex compilation_mutex;
+} DRWDeferredShader;
+
+typedef struct DRWShaderCompiler {
+ ListBase queue; /* DRWDeferredShader */
+ ThreadMutex list_mutex;
+
+ DRWDeferredShader *mat_compiling;
+ ThreadMutex compilation_mutex;
+
+ TaskScheduler *task_scheduler; /* NULL if nothing is running. */
+ TaskPool *task_pool;
+
+ void *ogl_context;
+} 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);
+ MEM_SAFE_FREE(dsh->defs);
+
+ MEM_freeN(dsh);
+}
+
+static void drw_deferred_shader_compilation_exec(TaskPool * __restrict UNUSED(pool), void *UNUSED(taskdata), int UNUSED(threadid))
+{
+ WM_opengl_context_activate(DSC.ogl_context);
+
+ while (true) {
+ BLI_mutex_lock(&DSC.list_mutex);
+ DSC.mat_compiling = BLI_pophead(&DSC.queue);
+ if (DSC.mat_compiling == NULL) {
+ break;
+ }
+ BLI_mutex_lock(&DSC.compilation_mutex);
+ BLI_mutex_unlock(&DSC.list_mutex);
+
+ /* 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);
+
+ BLI_mutex_unlock(&DSC.compilation_mutex);
+
+ drw_deferred_shader_free(DSC.mat_compiling);
+ }
+
+ WM_opengl_context_release(DSC.ogl_context);
+ BLI_mutex_unlock(&DSC.list_mutex);
+}
+
+static void drw_deferred_shader_add(
+ GPUMaterial *mat, const char *vert, const char *geom, const char *frag_lib, const char *defines)
+{
+ if (DRW_state_is_image_render()) {
+ /* Do not deferre the compilation if we are rendering for image. */
+ GPU_material_generate_pass(mat, vert, geom, frag_lib, defines);
+ return;
+ }
+
+ DRWDeferredShader *dsh = MEM_callocN(sizeof(DRWDeferredShader), "Deferred Shader");
+
+ dsh->mat = mat;
+ if (vert) dsh->vert = BLI_strdup(vert);
+ if (geom) dsh->geom = BLI_strdup(geom);
+ 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;
+
+ 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);
+}
+
+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);
+ }
+}
+
+
+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;
+ }
+}
+
+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();
+}
+
+void DRW_deferred_compiler_exit(void)
+{
+ drw_deferred_compiler_finish();
+ WM_opengl_context_dispose(DSC.ogl_context);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
GPUShader *DRW_shader_create(const char *vert, const char *geom, const char *frag, const char *defines)
{
return GPU_shader_create(vert, frag, geom, NULL, defines);
@@ -84,6 +250,32 @@ GPUShader *DRW_shader_create_3D_depth_only(void)
return GPU_shader_get_builtin_shader(GPU_SHADER_3D_DEPTH_ONLY);
}
+GPUMaterial *DRW_shader_create_from_world(
+ struct Scene *scene, World *wo, const void *engine_type, int options,
+ const char *vert, const char *geom, const char *frag_lib, const char *defines)
+{
+ GPUMaterial *mat = GPU_material_from_nodetree(
+ scene, wo->nodetree, &wo->gpumaterial, engine_type, options,
+ vert, geom, frag_lib, defines, true);
+
+ drw_deferred_shader_add(mat, vert, geom, frag_lib, defines);
+
+ return mat;
+}
+
+GPUMaterial *DRW_shader_create_from_material(
+ struct Scene *scene, Material *ma, const void *engine_type, int options,
+ const char *vert, const char *geom, const char *frag_lib, const char *defines)
+{
+ GPUMaterial *mat = GPU_material_from_nodetree(
+ scene, ma->nodetree, &ma->gpumaterial, engine_type, options,
+ vert, geom, frag_lib, defines, true);
+
+ drw_deferred_shader_add(mat, vert, geom, frag_lib, defines);
+
+ return mat;
+}
+
void DRW_shader_free(GPUShader *shader)
{
GPU_shader_free(shader);