diff options
Diffstat (limited to 'source/blender/draw/intern')
-rw-r--r-- | source/blender/draw/intern/DRW_render.h | 43 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_manager.c | 257 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_manager.h | 2 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_manager_shader.c | 20 |
4 files changed, 257 insertions, 65 deletions
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index f732082018d..4d1b8269494 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -44,6 +44,7 @@ #include "DNA_lamp_types.h" #include "DNA_material_types.h" #include "DNA_scene_types.h" +#include "DNA_world_types.h" #include "GPU_framebuffer.h" #include "GPU_texture.h" @@ -239,14 +240,14 @@ 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_find_from_world(struct World *wo, const void *engine_type, int options); -struct GPUMaterial *DRW_shader_find_from_material(struct Material *ma, const void *engine_type, int options); +struct GPUMaterial *DRW_shader_find_from_world(struct World *wo, const void *engine_type, int options, bool no_deferred); +struct GPUMaterial *DRW_shader_find_from_material(struct Material *ma, const void *engine_type, int options, bool no_deferred); 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); + const char *vert, const char *geom, const char *frag_lib, const char *defines, bool no_deferred); 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); + const char *vert, const char *geom, const char *frag_lib, const char *defines, bool no_deferred); void DRW_shader_free(struct GPUShader *shader); #define DRW_SHADER_FREE_SAFE(shader) do { \ if (shader != NULL) { \ @@ -409,6 +410,7 @@ void DRW_pass_sort_shgroup_z(DRWPass *pass); /* Viewport */ typedef enum { + /* keep in sync with the union struct DRWMatrixState. */ DRW_MAT_PERS = 0, DRW_MAT_PERSINV, DRW_MAT_VIEW, @@ -420,7 +422,18 @@ typedef enum { } DRWViewportMatrixType; typedef struct DRWMatrixState { - float mat[DRW_MAT_COUNT][4][4]; + union { + float mat[DRW_MAT_COUNT][4][4]; + struct { + /* keep in sync with the enum DRWViewportMatrixType. */ + float persmat[4][4]; + float persinv[4][4]; + float viewmat[4][4]; + float viewinv[4][4]; + float winmat[4][4]; + float wininv[4][4]; + }; + }; } DRWMatrixState; void DRW_viewport_init(const bContext *C); @@ -453,6 +466,12 @@ void DRW_render_object_iter( void (*callback)(void *vedata, struct Object *ob, struct RenderEngine *engine, struct Depsgraph *depsgraph)); void DRW_render_instance_buffer_finish(void); +void DRW_custom_pipeline( + DrawEngineType *draw_engine_type, + struct Depsgraph *depsgraph, + void (*callback)(void *vedata, void *user_data), + void *user_data); + /* ViewLayers */ void *DRW_view_layer_engine_data_get(DrawEngineType *engine_type); void **DRW_view_layer_engine_data_ensure_ex( @@ -460,16 +479,14 @@ void **DRW_view_layer_engine_data_ensure_ex( void **DRW_view_layer_engine_data_ensure( DrawEngineType *engine_type, void (*callback)(void *storage)); -/* Objects */ -ObjectEngineData *DRW_object_engine_data_get(Object *ob, DrawEngineType *engine_type); -ObjectEngineData *DRW_object_engine_data_ensure( - Object *ob, +/* DrawData */ +DrawData *DRW_drawdata_get(ID *ib, DrawEngineType *engine_type); +DrawData *DRW_drawdata_ensure( + ID *id, DrawEngineType *engine_type, size_t size, - ObjectEngineDataInitCb init_cb, - ObjectEngineDataFreeCb free_cb); -struct LampEngineData *DRW_lamp_engine_data_ensure(Object *ob, struct RenderEngineType *engine_type); -void DRW_lamp_engine_data_free(struct LampEngineData *led); + DrawDataInitCb init_cb, + DrawDataFreeCb free_cb); /* Settings */ bool DRW_object_is_renderable(struct Object *ob); diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index a1e44e479d4..30f7742fd35 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -44,6 +44,7 @@ #include "DNA_camera_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "DNA_world_types.h" #include "ED_space_api.h" #include "ED_screen.h" @@ -696,34 +697,96 @@ void **DRW_view_layer_engine_data_ensure(DrawEngineType *engine_type, void (*cal /* -------------------------------------------------------------------- */ -/** \name Objects (DRW_object) +/** \name Draw Data (DRW_drawdata) * \{ */ -ObjectEngineData *DRW_object_engine_data_get(Object *ob, DrawEngineType *engine_type) +/* Used for DRW_drawdata_from_id() + * All ID-datablocks which have their own 'local' DrawData + * should have the same arrangement in their structs. + */ +typedef struct IdDdtTemplate { + ID id; + struct AnimData *adt; + DrawDataList drawdata; +} IdDdtTemplate; + +/* Check if ID can have AnimData */ +static bool id_type_can_have_drawdata(const short id_type) +{ + /* Only some ID-blocks have this info for now */ + /* TODO: finish adding this for the other blocktypes */ + switch (id_type) { + /* has DrawData */ + case ID_OB: + case ID_WO: + return true; + + /* no DrawData */ + default: + return false; + } +} + +static bool id_can_have_drawdata(const ID *id) +{ + /* sanity check */ + if (id == NULL) + return false; + + return id_type_can_have_drawdata(GS(id->name)); +} + +/* Get DrawData from the given ID-block. In order for this to work, we assume that + * the DrawData pointer is stored in the struct in the same fashion as in IdDdtTemplate. + */ +DrawDataList *DRW_drawdatalist_from_id(ID *id) { - for (ObjectEngineData *oed = ob->drawdata.first; oed; oed = oed->next) { - if (oed->engine_type == engine_type) { - return oed; + /* only some ID-blocks have this info for now, so we cast the + * types that do to be of type IdDdtTemplate, and extract the + * DrawData that way + */ + if (id_can_have_drawdata(id)) { + IdDdtTemplate *idt = (IdDdtTemplate *)id; + return &idt->drawdata; + } + else + return NULL; +} + +DrawData *DRW_drawdata_get(ID *id, DrawEngineType *engine_type) +{ + DrawDataList *drawdata = DRW_drawdatalist_from_id(id); + + if (drawdata == NULL) + return NULL; + + LISTBASE_FOREACH(DrawData *, dd, drawdata) { + if (dd->engine_type == engine_type) { + return dd; } } return NULL; } -ObjectEngineData *DRW_object_engine_data_ensure( - Object *ob, +DrawData *DRW_drawdata_ensure( + ID *id, DrawEngineType *engine_type, size_t size, - ObjectEngineDataInitCb init_cb, - ObjectEngineDataFreeCb free_cb) + DrawDataInitCb init_cb, + DrawDataFreeCb free_cb) { - BLI_assert(size >= sizeof(ObjectEngineData)); + BLI_assert(size >= sizeof(DrawData)); + BLI_assert(id_can_have_drawdata(id)); /* Try to re-use existing data. */ - ObjectEngineData *oed = DRW_object_engine_data_get(ob, engine_type); - if (oed != NULL) { - return oed; + DrawData *dd = DRW_drawdata_get(id, engine_type); + if (dd != NULL) { + return dd; } + + DrawDataList *drawdata = DRW_drawdatalist_from_id(id); + /* Allocate new data. */ - if ((ob->base_flag & BASE_FROMDUPLI) != 0) { + if ((GS(id->name) == ID_OB) && (((Object *)id)->base_flag & BASE_FROMDUPLI) != 0) { /* NOTE: data is not persistent in this case. It is reset each redraw. */ BLI_assert(free_cb == NULL); /* No callback allowed. */ /* Round to sizeof(float) for DRW_instance_data_request(). */ @@ -734,21 +797,37 @@ ObjectEngineData *DRW_object_engine_data_ensure( if (DST.object_instance_data[fsize] == NULL) { DST.object_instance_data[fsize] = DRW_instance_data_request(DST.idatalist, fsize); } - oed = (ObjectEngineData *)DRW_instance_data_next(DST.object_instance_data[fsize]); - memset(oed, 0, size); + dd = (DrawData *)DRW_instance_data_next(DST.object_instance_data[fsize]); + memset(dd, 0, size); } else { - oed = MEM_callocN(size, "ObjectEngineData"); + dd = MEM_callocN(size, "DrawData"); } - oed->engine_type = engine_type; - oed->free = free_cb; + dd->engine_type = engine_type; + dd->free = free_cb; /* Perform user-side initialization, if needed. */ if (init_cb != NULL) { - init_cb(oed); + init_cb(dd); } /* Register in the list. */ - BLI_addtail(&ob->drawdata, oed); - return oed; + BLI_addtail((ListBase *)drawdata, dd); + return dd; +} + +void DRW_drawdata_free(ID *id) +{ + DrawDataList *drawdata = DRW_drawdatalist_from_id(id); + + if (drawdata == NULL) + return; + + LISTBASE_FOREACH(DrawData *, dd, drawdata) { + if (dd->free != NULL) { + dd->free(dd); + } + } + + BLI_freelistN((ListBase *)drawdata); } /** \} */ @@ -794,6 +873,22 @@ static void drw_engines_cache_init(void) } } +static void drw_engines_world_update(Scene *scene) +{ + if (scene->world == NULL) { + return; + } + + for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { + DrawEngineType *engine = link->data; + ViewportEngineData *data = drw_viewport_engine_data_ensure(engine); + + if (engine->id_update) { + engine->id_update(data, &scene->world->id); + } + } +} + static void drw_engines_cache_populate(Object *ob) { DST.ob_state = NULL; @@ -1161,7 +1256,7 @@ void DRW_notify_view_update(const DRWUpdateContext *update_ctx) /* XXX Really nasty locking. But else this could * be executed by the material previews thread * while rendering a viewport. */ - BLI_mutex_lock(&DST.gl_context_mutex); + BLI_ticket_mutex_lock(DST.gl_context_mutex); /* Reset before using it. */ drw_state_prepare_clean_for_draw(&DST); @@ -1189,7 +1284,7 @@ void DRW_notify_view_update(const DRWUpdateContext *update_ctx) drw_engines_disable(); - BLI_mutex_unlock(&DST.gl_context_mutex); + BLI_ticket_mutex_unlock(DST.gl_context_mutex); } } @@ -1273,6 +1368,7 @@ void DRW_draw_render_loop_ex( { PROFILE_START(stime); drw_engines_cache_init(); + drw_engines_world_update(scene); const int object_type_exclude_viewport = v3d->object_type_exclude_viewport; DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(depsgraph, ob) @@ -1458,14 +1554,10 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph) /* Changing Context */ if (re_gl_context != NULL) { - /* TODO get rid of the blocking. Only here because of the static global DST. */ - BLI_mutex_lock(&DST.gl_context_mutex); - WM_opengl_context_activate(re_gl_context); + DRW_opengl_render_context_enable(re_gl_context); + /* We need to query gwn context after a gl context has been bound. */ re_gwn_context = RE_gwn_context_get(render); - if (GWN_context_active_get() == NULL) { - GWN_context_active_set(re_gwn_context); - } - DRW_shape_cache_reset(); /* XXX fix that too. */ + DRW_gawain_render_context_enable(re_gwn_context); } else { DRW_opengl_context_enable(); @@ -1544,12 +1636,8 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph) /* Changing Context */ if (re_gl_context != NULL) { - DRW_shape_cache_reset(); /* XXX fix that too. */ - glFlush(); - GWN_context_active_set(NULL); - WM_opengl_context_release(re_gl_context); - /* TODO get rid of the blocking. */ - BLI_mutex_unlock(&DST.gl_context_mutex); + DRW_gawain_render_context_disable(re_gwn_context); + DRW_opengl_render_context_disable(re_gl_context); } else { DRW_opengl_context_disable(); @@ -1575,6 +1663,56 @@ void DRW_render_object_iter( DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END } +/* Assume a valid gl context is bound (and that the gl_context_mutex has been aquired). + * This function only setup DST and execute the given function. + * Warning: similar to DRW_render_to_image you cannot use default lists (dfbl & dtxl). */ +void DRW_custom_pipeline( + DrawEngineType *draw_engine_type, + struct Depsgraph *depsgraph, + void (*callback)(void *vedata, void *user_data), + void *user_data) +{ + Scene *scene = DEG_get_evaluated_scene(depsgraph); + ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph); + + /* Reset before using it. */ + drw_state_prepare_clean_for_draw(&DST); + DST.options.is_image_render = true; + DST.options.is_scene_render = true; + DST.options.draw_background = false; + + DST.draw_ctx = (DRWContextState){ + .scene = scene, + .view_layer = view_layer, + .engine_type = NULL, + .depsgraph = depsgraph, + .object_mode = OB_MODE_OBJECT, + }; + drw_context_state_init(); + + DST.viewport = GPU_viewport_create(); + const int size[2] = {1, 1}; + GPU_viewport_size_set(DST.viewport, size); + + drw_viewport_var_init(); + + DRW_hair_init(); + + ViewportEngineData *data = drw_viewport_engine_data_ensure(draw_engine_type); + + /* Execute the callback */ + callback(data, user_data); + DST.buffer_finish_called = false; + + GPU_viewport_free(DST.viewport); + GPU_framebuffer_restore(); + +#ifdef DEBUG + /* Avoid accidental reuse. */ + drw_state_ensure_not_reused(&DST); +#endif +} + static struct DRWSelectBuffer { struct GPUFrameBuffer *framebuffer; struct GPUTexture *texture_depth; @@ -1697,6 +1835,7 @@ void DRW_draw_select_loop( { drw_engines_cache_init(); + drw_engines_world_update(scene); if (use_obedit) { #if 0 @@ -1891,6 +2030,7 @@ void DRW_draw_depth_loop( { drw_engines_cache_init(); + drw_engines_world_update(scene); const int object_type_exclude_viewport = v3d->object_type_exclude_viewport; DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(depsgraph, ob) @@ -2182,7 +2322,7 @@ void DRW_opengl_context_create(void) { BLI_assert(DST.gl_context == NULL); /* Ensure it's called once */ - BLI_mutex_init(&DST.gl_context_mutex); + DST.gl_context_mutex = BLI_ticket_mutex_alloc(); if (!G.background) { immDeactivate(); } @@ -2207,7 +2347,7 @@ void DRW_opengl_context_destroy(void) GWN_context_active_set(DST.gwn_context); GWN_context_discard(DST.gwn_context); WM_opengl_context_dispose(DST.gl_context); - BLI_mutex_end(&DST.gl_context_mutex); + BLI_ticket_mutex_free(DST.gl_context_mutex); } } @@ -2217,7 +2357,7 @@ void DRW_opengl_context_enable(void) /* IMPORTANT: We dont support immediate mode in render mode! * This shall remain in effect until immediate mode supports * multiple threads. */ - BLI_mutex_lock(&DST.gl_context_mutex); + BLI_ticket_mutex_lock(DST.gl_context_mutex); if (BLI_thread_is_main()) { if (!G.background) { immDeactivate(); @@ -2251,8 +2391,43 @@ void DRW_opengl_context_disable(void) GWN_context_active_set(NULL); } - BLI_mutex_unlock(&DST.gl_context_mutex); + BLI_ticket_mutex_unlock(DST.gl_context_mutex); } } +void DRW_opengl_render_context_enable(void *re_gl_context) +{ + /* If thread is main you should use DRW_opengl_context_enable(). */ + BLI_assert(!BLI_thread_is_main()); + + /* TODO get rid of the blocking. Only here because of the static global DST. */ + BLI_ticket_mutex_lock(DST.gl_context_mutex); + WM_opengl_context_activate(re_gl_context); +} + +void DRW_opengl_render_context_disable(void *re_gl_context) +{ + glFlush(); + WM_opengl_context_release(re_gl_context); + /* TODO get rid of the blocking. */ + BLI_ticket_mutex_unlock(DST.gl_context_mutex); +} + +/* Needs to be called AFTER DRW_opengl_render_context_enable() */ +void DRW_gawain_render_context_enable(void *re_gwn_context) +{ + /* If thread is main you should use DRW_opengl_context_enable(). */ + BLI_assert(!BLI_thread_is_main()); + + GWN_context_active_set(re_gwn_context); + DRW_shape_cache_reset(); /* XXX fix that too. */ +} + +/* Needs to be called BEFORE DRW_opengl_render_context_disable() */ +void DRW_gawain_render_context_disable(void *UNUSED(re_gwn_context)) +{ + DRW_shape_cache_reset(); /* XXX fix that too. */ + GWN_context_active_set(NULL); +} + /** \} */ diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h index 91a30fa45ae..6eae3459c2b 100644 --- a/source/blender/draw/intern/draw_manager.h +++ b/source/blender/draw/intern/draw_manager.h @@ -373,7 +373,7 @@ typedef struct DRWManager { * the top portion of the struct so DO NOT MOVE IT! */ void *gl_context; /* Unique ghost context used by the draw manager. */ Gwn_Context *gwn_context; - ThreadMutex gl_context_mutex; /* Mutex to lock the drw manager and avoid concurent context usage. */ + TicketMutex *gl_context_mutex; /* Mutex to lock the drw manager and avoid concurent context usage. */ /** GPU Resource State: Memory storage between drawing. */ struct { diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c index 435c6c77e59..b0aec4a7600 100644 --- a/source/blender/draw/intern/draw_manager_shader.c +++ b/source/blender/draw/intern/draw_manager_shader.c @@ -154,10 +154,10 @@ static void drw_deferred_shader_compilation_free(void *custom_data) MEM_freeN(comp); } -static void drw_deferred_shader_add(GPUMaterial *mat) +static void drw_deferred_shader_add(GPUMaterial *mat, bool deferred) { /* Do not deferre the compilation if we are rendering for image. */ - if (DRW_state_is_image_render() || !USE_DEFERRED_COMPILATION) { + if (DRW_state_is_image_render() || !USE_DEFERRED_COMPILATION || !deferred) { /* Double checking that this GPUMaterial is not going to be * compiled by another thread. */ DRW_deferred_shader_remove(mat); @@ -308,10 +308,10 @@ GPUShader *DRW_shader_create_3D_depth_only(void) return GPU_shader_get_builtin_shader(GPU_SHADER_3D_DEPTH_ONLY); } -GPUMaterial *DRW_shader_find_from_world(World *wo, const void *engine_type, int options) +GPUMaterial *DRW_shader_find_from_world(World *wo, const void *engine_type, int options, bool deferred) { GPUMaterial *mat = GPU_material_from_nodetree_find(&wo->gpumaterial, engine_type, options); - if (DRW_state_is_image_render()) { + if (DRW_state_is_image_render() || !deferred) { if (mat != NULL && GPU_material_status(mat) == GPU_MAT_QUEUED) { /* XXX Hack : we return NULL so that the engine will call DRW_shader_create_from_XXX * with the shader code and we will resume the compilation from there. */ @@ -321,10 +321,10 @@ GPUMaterial *DRW_shader_find_from_world(World *wo, const void *engine_type, int return mat; } -GPUMaterial *DRW_shader_find_from_material(Material *ma, const void *engine_type, int options) +GPUMaterial *DRW_shader_find_from_material(Material *ma, const void *engine_type, int options, bool deferred) { GPUMaterial *mat = GPU_material_from_nodetree_find(&ma->gpumaterial, engine_type, options); - if (DRW_state_is_image_render()) { + if (DRW_state_is_image_render() || !deferred) { if (mat != NULL && GPU_material_status(mat) == GPU_MAT_QUEUED) { /* XXX Hack : we return NULL so that the engine will call DRW_shader_create_from_XXX * with the shader code and we will resume the compilation from there. */ @@ -336,7 +336,7 @@ GPUMaterial *DRW_shader_find_from_material(Material *ma, const void *engine_type 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) + const char *vert, const char *geom, const char *frag_lib, const char *defines, bool deferred) { GPUMaterial *mat = NULL; if (DRW_state_is_image_render()) { @@ -350,7 +350,7 @@ GPUMaterial *DRW_shader_create_from_world( } if (GPU_material_status(mat) == GPU_MAT_QUEUED) { - drw_deferred_shader_add(mat); + drw_deferred_shader_add(mat, deferred); } return mat; @@ -358,7 +358,7 @@ GPUMaterial *DRW_shader_create_from_world( 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) + const char *vert, const char *geom, const char *frag_lib, const char *defines, bool deferred) { GPUMaterial *mat = NULL; if (DRW_state_is_image_render()) { @@ -372,7 +372,7 @@ GPUMaterial *DRW_shader_create_from_material( } if (GPU_material_status(mat) == GPU_MAT_QUEUED) { - drw_deferred_shader_add(mat); + drw_deferred_shader_add(mat, deferred); } return mat; |