diff options
-rw-r--r-- | intern/cycles/blender/addon/ui.py | 2 | ||||
-rw-r--r-- | intern/cycles/blender/blender_session.cpp | 36 | ||||
-rw-r--r-- | intern/cycles/blender/blender_sync.cpp | 14 | ||||
-rw-r--r-- | intern/cycles/render/scene.cpp | 2 | ||||
-rw-r--r-- | intern/cycles/render/scene.h | 6 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/scene.c | 15 | ||||
-rw-r--r-- | source/blender/depsgraph/DEG_depsgraph.h | 24 | ||||
-rw-r--r-- | source/blender/depsgraph/intern/depsgraph.cc | 7 | ||||
-rw-r--r-- | source/blender/depsgraph/intern/depsgraph.h | 3 | ||||
-rw-r--r-- | source/blender/depsgraph/intern/depsgraph_tag.cc | 17 | ||||
-rw-r--r-- | source/blender/editors/render/render_update.c | 2 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_render.c | 6 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_scene.c | 12 | ||||
-rw-r--r-- | source/blender/render/RE_engine.h | 2 | ||||
-rw-r--r-- | source/blender/render/RE_pipeline.h | 14 | ||||
-rw-r--r-- | source/blender/render/intern/engine.c | 131 | ||||
-rw-r--r-- | source/blender/render/intern/pipeline.c | 61 |
17 files changed, 229 insertions, 125 deletions
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 28fc48f33d3..73bc114893a 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -775,7 +775,7 @@ class CYCLES_RENDER_PT_performance_final_render(CyclesButtonsPanel, Panel): col = layout.column() col.prop(rd, "use_save_buffers") - col.prop(rd, "use_persistent_data", text="Persistent Images") + col.prop(rd, "use_persistent_data", text="Persistent Data") class CYCLES_RENDER_PT_performance_viewport(CyclesButtonsPanel, Panel): diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index ae13310789e..bf4d80ce51b 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -143,12 +143,6 @@ void BlenderSession::create_session() session->scene = scene; - /* There is no single depsgraph to use for the entire render. - * So we need to handle this differently. - * - * We could loop over the final render result render layers in pipeline and keep Cycles unaware - * of multiple layers, or perhaps move syncing further down in the pipeline. - */ /* create sync */ sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress); BL::Object b_camera_override(b_engine.camera_override()); @@ -213,7 +207,7 @@ void BlenderSession::reset_session(BL::BlendData &b_data, BL::Depsgraph &b_depsg SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background); if (scene->params.modified(scene_params) || session->params.modified(session_params) || - !scene_params.persistent_data) { + !this->b_render.use_persistent_data()) { /* if scene or session parameters changed, it's easier to simply re-create * them rather than trying to distinguish which settings need to be updated */ @@ -225,7 +219,6 @@ void BlenderSession::reset_session(BL::BlendData &b_data, BL::Depsgraph &b_depsg } session->progress.reset(); - scene->reset(); session->tile_manager.set_tile_order(session_params.tile_order); @@ -234,12 +227,15 @@ void BlenderSession::reset_session(BL::BlendData &b_data, BL::Depsgraph &b_depsg */ session->stats.mem_peak = session->stats.mem_used; - /* There is no single depsgraph to use for the entire render. - * See note on create_session(). - */ - /* sync object should be re-created */ - delete sync; - sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress); + if (is_new_session) { + /* Sync object should be re-created for new scene. */ + delete sync; + sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress); + } + else { + /* Sync recalculations to do just the required updates. */ + sync->sync_recalc(b_depsgraph, b_v3d); + } BL::SpaceView3D b_null_space_view3d(PointerRNA_NULL); BL::RegionView3D b_null_region_view3d(PointerRNA_NULL); @@ -598,18 +594,6 @@ void BlenderSession::render(BL::Depsgraph &b_depsgraph_) /* clear callback */ session->write_render_tile_cb = function_null; session->update_render_tile_cb = function_null; - - /* TODO: find a way to clear this data for persistent data render */ -#if 0 - /* free all memory used (host and device), so we wouldn't leave render - * engine with extra memory allocated - */ - - session->device_free(); - - delete sync; - sync = NULL; -#endif } static int bake_pass_filter_get(const int pass_filter) diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index bbeb6858b76..09bc329041f 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -211,9 +211,11 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d } } - BlenderViewportParameters new_viewport_parameters(b_v3d); - if (viewport_parameters.modified(new_viewport_parameters)) { - world_recalc = true; + if (b_v3d) { + BlenderViewportParameters new_viewport_parameters(b_v3d); + if (viewport_parameters.modified(new_viewport_parameters)) { + world_recalc = true; + } } } @@ -757,7 +759,6 @@ void BlenderSync::free_data_after_sync(BL::Depsgraph &b_depsgraph) SceneParams BlenderSync::get_scene_params(BL::Scene &b_scene, bool background) { - BL::RenderSettings r = b_scene.render(); SceneParams params; PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); const bool shadingsystem = RNA_boolean_get(&cscene, "shading_system"); @@ -781,11 +782,6 @@ SceneParams BlenderSync::get_scene_params(BL::Scene &b_scene, bool background) params.hair_shape = (CurveShapeType)get_enum( csscene, "shape", CURVE_NUM_SHAPE_TYPES, CURVE_THICK); - if (background && params.shadingsystem != SHADINGSYSTEM_OSL) - params.persistent_data = r.use_persistent_data(); - else - params.persistent_data = false; - int texture_limit; if (background) { texture_limit = RNA_enum_get(&cscene, "texture_limit_render"); diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index d3dfe1c5be6..38e8d9145dc 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -179,7 +179,7 @@ void Scene::free_memory(bool final) bake_manager->device_free(device, &dscene); - if (!params.persistent_data || final) + if (final) image_manager->device_free(device); else image_manager->device_free_builtin(device); diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h index 61c753e411c..3e7de203c54 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -178,7 +178,6 @@ class SceneParams { int num_bvh_time_steps; int hair_subdivisions; CurveShapeType hair_shape; - bool persistent_data; int texture_limit; bool background; @@ -193,7 +192,6 @@ class SceneParams { num_bvh_time_steps = 0; hair_subdivisions = 3; hair_shape = CURVE_RIBBON; - persistent_data = false; texture_limit = 0; background = true; } @@ -206,7 +204,7 @@ class SceneParams { use_bvh_unaligned_nodes == params.use_bvh_unaligned_nodes && num_bvh_time_steps == params.num_bvh_time_steps && hair_subdivisions == params.hair_subdivisions && hair_shape == params.hair_shape && - persistent_data == params.persistent_data && texture_limit == params.texture_limit); + texture_limit == params.texture_limit); } int curve_subdivisions() @@ -301,7 +299,7 @@ class Scene : public NodeOwner { * node array (e.g. Scene::geometry for Geometry nodes) and tag the appropriate * manager for an update. */ - template<typename T, typename... Args> T *create_node(Args &&... args) + template<typename T, typename... Args> T *create_node(Args &&...args) { T *node = new T(args...); node->set_owner(this); diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index e0ff0b0268a..44c0fd5144b 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -2660,7 +2660,7 @@ static void scene_graph_update_tagged(Depsgraph *depsgraph, Main *bmain, bool on bmain, &scene->id, depsgraph, BKE_CB_EVT_DEPSGRAPH_UPDATE_POST); /* It is possible that the custom callback modified scene and removed some IDs from the main - * database. In this case DEG_ids_clear_recalc() will crash because it iterates over all IDs + * database. In this case DEG_editors_update() will crash because it iterates over all IDs * which depsgraph was built for. * * The solution is to update relations prior to this call, avoiding access to freed IDs. @@ -2673,9 +2673,7 @@ static void scene_graph_update_tagged(Depsgraph *depsgraph, Main *bmain, bool on DEG_graph_relations_update(depsgraph); } /* Inform editors about possible changes. */ - DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, false); - /* Clear recalc flags. */ - DEG_ids_clear_recalc(bmain, depsgraph); + DEG_editors_update(bmain, depsgraph, scene, view_layer, false); /* If user callback did not tag anything for update we can skip second iteration. * Otherwise we update scene once again, but without running callbacks to bring @@ -2736,14 +2734,12 @@ void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph) BKE_callback_exec_id_depsgraph(bmain, &scene->id, depsgraph, BKE_CB_EVT_FRAME_CHANGE_POST); /* NOTE: Similar to this case in scene_graph_update_tagged(). Need to ensure that - * DEG_ids_clear_recalc() doesn't access freed memory of possibly removed ID. */ + * DEG_editors_update() doesn't access freed memory of possibly removed ID. */ DEG_graph_relations_update(depsgraph); } /* Inform editors about possible changes. */ - DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, true); - /* clear recalc flags */ - DEG_ids_clear_recalc(bmain, depsgraph); + DEG_editors_update(bmain, depsgraph, scene, view_layer, true); /* If user callback did not tag anything for update we can skip second iteration. * Otherwise we update scene once again, but without running callbacks to bring @@ -3462,6 +3458,9 @@ static Depsgraph **scene_ensure_depsgraph_p(Main *bmain, Scene *scene, ViewLayer BLI_snprintf(name, sizeof(name), "%s :: %s", scene->id.name, view_layer->name); DEG_debug_name_set(*depsgraph_ptr, name); + /* These viewport depsgraphs communicate changes to the editors. */ + DEG_enable_editors_update(*depsgraph_ptr); + return depsgraph_ptr; } diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h index 567916fdebe..f7aeca7e75f 100644 --- a/source/blender/depsgraph/DEG_depsgraph.h +++ b/source/blender/depsgraph/DEG_depsgraph.h @@ -139,16 +139,20 @@ void DEG_graph_time_tag_update(struct Depsgraph *depsgraph); void DEG_graph_id_type_tag(struct Depsgraph *depsgraph, short id_type); void DEG_id_type_tag(struct Main *bmain, short id_type); -void DEG_ids_clear_recalc(struct Main *bmain, Depsgraph *depsgraph); - -/* Check if something was changed in the database and inform - * editors about this. - */ -void DEG_ids_check_recalc(struct Main *bmain, - struct Depsgraph *depsgraph, - struct Scene *scene, - struct ViewLayer *view_layer, - bool time); +/* Set a depsgraph to flush updates to editors. This would be done + * for viewport depsgraphs, but not render or export depsgraph for example. */ +void DEG_enable_editors_update(struct Depsgraph *depsgraph); + +/* Check if something was changed in the database and inform editors about this, + * then clear recalc flags. */ +void DEG_editors_update(struct Main *bmain, + struct Depsgraph *depsgraph, + struct Scene *scene, + struct ViewLayer *view_layer, + bool time); + +/* Clear recalc flags after editors or renderers have handled updates. */ +void DEG_ids_clear_recalc(Depsgraph *depsgraph); /* ************************************************ */ /* Evaluation Engine API */ diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc index 3d30e7e79b9..8e1ab23fae0 100644 --- a/source/blender/depsgraph/intern/depsgraph.cc +++ b/source/blender/depsgraph/intern/depsgraph.cc @@ -70,7 +70,8 @@ Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluati scene_cow(nullptr), is_active(false), is_evaluating(false), - is_render_pipeline_depsgraph(false) + is_render_pipeline_depsgraph(false), + use_editors_update(false) { BLI_spin_init(&lock); memset(id_type_updated, 0, sizeof(id_type_updated)); @@ -285,7 +286,9 @@ Depsgraph *DEG_graph_new(Main *bmain, Scene *scene, ViewLayer *view_layer, eEval } /* Replace the "owner" pointers (currently Main/Scene/ViewLayer) of this depsgraph. - * Used during undo steps when we do want to re-use the old depsgraph data as much as possible. */ + * Used for: + * - Undo steps when we do want to re-use the old depsgraph data as much as possible. + * - Rendering where we want to re-use objects between different view layers. */ void DEG_graph_replace_owners(struct Depsgraph *depsgraph, Main *bmain, Scene *scene, diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h index df8c8215d2f..d54aba8e25d 100644 --- a/source/blender/depsgraph/intern/depsgraph.h +++ b/source/blender/depsgraph/intern/depsgraph.h @@ -161,6 +161,9 @@ struct Depsgraph { * does not need any bases. */ bool is_render_pipeline_depsgraph; + /* Notify editors about changes to IDs in this depsgrpah. */ + bool use_editors_update; + /* Cached list of colliders/effectors for collections and the scene * created along with relations, for fast lookup during evaluation. */ Map<const ID *, ListBase *> *physics_relations[DEG_PHYSICS_RELATIONS_NUM]; diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index 2051ee3657a..504c3956d03 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -816,11 +816,22 @@ void DEG_on_visible_update(Main *bmain, const bool do_time) } } +void DEG_enable_editors_update(Depsgraph *depsgraph) +{ + deg::Depsgraph *graph = (deg::Depsgraph *)depsgraph; + graph->use_editors_update = true; +} + /* Check if something was changed in the database and inform * editors about this. */ -void DEG_ids_check_recalc( +void DEG_editors_update( Main *bmain, Depsgraph *depsgraph, Scene *scene, ViewLayer *view_layer, bool time) { + deg::Depsgraph *graph = (deg::Depsgraph *)depsgraph; + if (!graph->use_editors_update) { + return; + } + bool updated = time || DEG_id_type_any_updated(depsgraph); DEGEditorUpdateContext update_ctx = {nullptr}; @@ -829,6 +840,8 @@ void DEG_ids_check_recalc( update_ctx.scene = scene; update_ctx.view_layer = view_layer; deg::deg_editors_scene_update(&update_ctx, updated); + + DEG_ids_clear_recalc(depsgraph); } static void deg_graph_clear_id_recalc_flags(ID *id) @@ -842,7 +855,7 @@ static void deg_graph_clear_id_recalc_flags(ID *id) /* XXX And what about scene's master collection here? */ } -void DEG_ids_clear_recalc(Main *UNUSED(bmain), Depsgraph *depsgraph) +void DEG_ids_clear_recalc(Depsgraph *depsgraph) { deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(depsgraph); /* TODO(sergey): Re-implement POST_UPDATE_HANDLER_WORKAROUND using entry_tags diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c index 4ed1cbd60a5..3e8a1bda2f0 100644 --- a/source/blender/editors/render/render_update.c +++ b/source/blender/editors/render/render_update.c @@ -188,7 +188,7 @@ void ED_render_engine_changed(Main *bmain, const bool update_scene_data) ED_render_engine_area_exit(bmain, area); } } - RE_FreePersistentData(); + RE_FreePersistentData(NULL); /* Inform all render engines and draw managers. */ DEGEditorUpdateContext update_ctx = {NULL}; update_ctx.bmain = bmain; diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c index 0411ef6d6ee..dd91a5509f5 100644 --- a/source/blender/makesrna/intern/rna_render.c +++ b/source/blender/makesrna/intern/rna_render.c @@ -298,13 +298,13 @@ static void rna_RenderEngine_unregister(Main *bmain, StructRNA *type) return; } + /* Stop all renders in case we were using this one. */ + ED_render_engine_changed(bmain, false); RE_FreeAllPersistentData(); + RNA_struct_free_extension(type, &et->rna_ext); RNA_struct_free(&BLENDER_RNA, type); BLI_freelinkN(&R_engines, et); - - /* Stop all renders in case we were using this one. */ - ED_render_engine_changed(bmain, false); } static StructRNA *rna_RenderEngine_register(Main *bmain, diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 65643aa92d7..cc7747959a4 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -1896,10 +1896,10 @@ static void rna_Scene_use_persistent_data_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { - Scene *sce = (Scene *)ptr->owner_id; + Scene *scene = (Scene *)ptr->owner_id; - if (!(sce->r.mode & R_PERSISTENT_DATA)) { - RE_FreePersistentData(); + if (!(scene->r.mode & R_PERSISTENT_DATA)) { + RE_FreePersistentData(scene); } } @@ -6606,8 +6606,10 @@ static void rna_def_scene_render_data(BlenderRNA *brna) /* persistent data */ prop = RNA_def_property(srna, "use_persistent_data", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "mode", R_PERSISTENT_DATA); - RNA_def_property_ui_text( - prop, "Persistent Data", "Keep render data around for faster re-renders"); + RNA_def_property_ui_text(prop, + "Persistent Data", + "Keep render data around for faster re-renders and animation renders, " + "at the cost of increased memory usage"); RNA_def_property_update(prop, 0, "rna_Scene_use_persistent_data_update"); /* Freestyle line thickness options */ diff --git a/source/blender/render/RE_engine.h b/source/blender/render/RE_engine.h index c31a41f66d5..f6ab7fd9d3c 100644 --- a/source/blender/render/RE_engine.h +++ b/source/blender/render/RE_engine.h @@ -224,6 +224,8 @@ void RE_engine_register_pass(struct RenderEngine *engine, const char *chanid, eNodeSocketDatatype type); +bool RE_engine_use_persistent_data(struct RenderEngine *engine); + /* Engine Types */ void RE_engines_init(void); diff --git a/source/blender/render/RE_pipeline.h b/source/blender/render/RE_pipeline.h index 27dcd9e70ed..7420ee64a81 100644 --- a/source/blender/render/RE_pipeline.h +++ b/source/blender/render/RE_pipeline.h @@ -184,14 +184,14 @@ void RE_InitRenderCB(struct Render *re); void RE_FreeRender(struct Render *re); /* only called on exit */ void RE_FreeAllRender(void); -/* Free memory used by persistent data. - * Invoked when loading new file. - */ -void RE_FreeAllPersistentData(void); -/* only call on file load */ + +/* On file load, free render results. */ void RE_FreeAllRenderResults(void); -/* for external render engines that can keep persistent data */ -void RE_FreePersistentData(void); +/* On file load or changes engines, free persistent render data. + * Assumes no engines are currently rendering. */ +void RE_FreeAllPersistentData(void); +/* Free persistent render data, optionally only for the given scene. */ +void RE_FreePersistentData(const Scene *scene); /* get results and statistics */ void RE_FreeRenderResult(struct RenderResult *rr); diff --git a/source/blender/render/intern/engine.c b/source/blender/render/intern/engine.c index a43a78f5d3d..ccb9996a143 100644 --- a/source/blender/render/intern/engine.c +++ b/source/blender/render/intern/engine.c @@ -140,6 +140,27 @@ RenderEngine *RE_engine_create(RenderEngineType *type) return engine; } +static void engine_depsgraph_free(RenderEngine *engine) +{ + if (engine->depsgraph) { + /* Need GPU context since this might free GPU buffers. This function can + * only be called from a render thread. We do not currently support + * persistent data with GPU contexts for that reason. */ + const bool use_gpu_context = (engine->type->flag & RE_USE_GPU_CONTEXT); + if (use_gpu_context) { + BLI_assert(!BLI_thread_is_main()); + DRW_render_context_enable(engine->re); + } + + DEG_graph_free(engine->depsgraph); + engine->depsgraph = NULL; + + if (use_gpu_context) { + DRW_render_context_disable(engine->re); + } + } +} + void RE_engine_free(RenderEngine *engine) { #ifdef WITH_PYTHON @@ -148,6 +169,8 @@ void RE_engine_free(RenderEngine *engine) } #endif + engine_depsgraph_free(engine); + BLI_mutex_end(&engine->update_render_passes_mutex); MEM_freeN(engine); @@ -598,34 +621,94 @@ RenderData *RE_engine_get_render_data(Render *re) return &re->r; } +bool RE_engine_use_persistent_data(RenderEngine *engine) +{ + /* See engine_depsgraph_free() for why preserving the depsgraph for + * re-renders is not supported with GPU contexts. */ + return (engine->re->r.mode & R_PERSISTENT_DATA) && !(engine->type->flag & RE_USE_GPU_CONTEXT); +} + +static bool engine_keep_depsgraph(RenderEngine *engine) +{ + /* For persistent data or GPU engines like Eevee, reuse the depsgraph between + * view layers and animation frames. For renderers like Cycles that create + * their own copy of the scene, persistent data must be explicitly enabled to + * keep memory usage low by default. */ + return (engine->re->r.mode & R_PERSISTENT_DATA) || (engine->type->flag & RE_USE_GPU_CONTEXT); +} + /* Depsgraph */ static void engine_depsgraph_init(RenderEngine *engine, ViewLayer *view_layer) { Main *bmain = engine->re->main; Scene *scene = engine->re->scene; + bool reuse_depsgraph = false; + + /* Reuse depsgraph from persistent data if possible. */ + if (engine->depsgraph) { + if (DEG_get_bmain(engine->depsgraph) != bmain || + DEG_get_input_scene(engine->depsgraph) != scene) { + /* If bmain or scene changes, we need a completely new graph. */ + engine_depsgraph_free(engine); + } + else if (DEG_get_input_view_layer(engine->depsgraph) != view_layer) { + /* If only view layer changed, reuse depsgraph in the hope of reusing + * objects shared between view layers. */ + DEG_graph_replace_owners(engine->depsgraph, bmain, scene, view_layer); + DEG_graph_tag_relations_update(engine->depsgraph); + } - engine->depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_RENDER); - DEG_debug_name_set(engine->depsgraph, "RENDER"); + reuse_depsgraph = true; + } + + if (!engine->depsgraph) { + /* Ensure we only use persistent data for one scene / view layer at a time, + * to avoid excessive memory usage. */ + RE_FreePersistentData(NULL); + + /* Create new depsgraph if not cached with persistent data. */ + engine->depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_RENDER); + DEG_debug_name_set(engine->depsgraph, "RENDER"); + } if (engine->re->r.scemode & R_BUTS_PREVIEW) { + /* Update for preview render. */ Depsgraph *depsgraph = engine->depsgraph; DEG_graph_relations_update(depsgraph); + + /* Need GPU context since this might free GPU buffers. */ + const bool use_gpu_context = (engine->type->flag & RE_USE_GPU_CONTEXT) && reuse_depsgraph; + if (use_gpu_context) { + DRW_render_context_enable(engine->re); + } + DEG_evaluate_on_framechange(depsgraph, CFRA); - DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, true); - DEG_ids_clear_recalc(bmain, depsgraph); + + if (use_gpu_context) { + DRW_render_context_disable(engine->re); + } } else { + /* Go through update with full Python callbacks for regular render. */ BKE_scene_graph_update_for_newframe(engine->depsgraph); } engine->has_grease_pencil = DRW_render_check_grease_pencil(engine->depsgraph); } -static void engine_depsgraph_free(RenderEngine *engine) +static void engine_depsgraph_exit(RenderEngine *engine) { - DEG_graph_free(engine->depsgraph); - - engine->depsgraph = NULL; + if (engine->depsgraph) { + if (engine_keep_depsgraph(engine)) { + /* Clear recalc flags since the engine should have handled the updates for the currently + * rendered framed by now. */ + DEG_ids_clear_recalc(engine->depsgraph); + } + else { + /* Free immediately to save memory. */ + engine_depsgraph_free(engine); + } + } } void RE_engine_frame_set(RenderEngine *engine, int frame, float subframe) @@ -670,7 +753,6 @@ bool RE_bake_engine(Render *re, { RenderEngineType *type = RE_engines_find(re->r.engine); RenderEngine *engine; - bool persistent_data = (re->r.mode & R_PERSISTENT_DATA) != 0; /* set render info */ re->i.cfra = re->scene->r.cfra; @@ -729,13 +811,13 @@ bool RE_bake_engine(Render *re, engine->tile_y = 0; engine->flag &= ~RE_ENGINE_RENDERING; + /* Free depsgraph outside of parts mutex lock, since this locks OpenGL context + * while the the UI drawing might also lock the OpenGL context and parts mutex. */ + engine_depsgraph_free(engine); BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_WRITE); - /* re->engine becomes zero if user changed active render engine during render */ - if (!persistent_data || !re->engine) { - RE_engine_free(engine); - re->engine = NULL; - } + RE_engine_free(engine); + re->engine = NULL; RE_parts_free(re); BLI_rw_mutex_unlock(&re->partsmutex); @@ -778,13 +860,14 @@ static void engine_render_view_layer(Render *re, /* Perform render with engine. */ if (use_engine) { - if (engine->type->flag & RE_USE_GPU_CONTEXT) { + const bool use_gpu_context = (engine->type->flag & RE_USE_GPU_CONTEXT); + if (use_gpu_context) { DRW_render_context_enable(engine->re); } engine->type->render(engine, engine->depsgraph); - if (engine->type->flag & RE_USE_GPU_CONTEXT) { + if (use_gpu_context) { DRW_render_context_disable(engine->re); } } @@ -800,13 +883,12 @@ static void engine_render_view_layer(Render *re, } /* Free dependency graph, if engine has not done it already. */ - engine_depsgraph_free(engine); + engine_depsgraph_exit(engine); } bool RE_engine_render(Render *re, bool do_all) { RenderEngineType *type = RE_engines_find(re->r.engine); - bool persistent_data = (re->r.mode & R_PERSISTENT_DATA) != 0; /* verify if we can render */ if (!type->render) { @@ -953,7 +1035,13 @@ bool RE_engine_render(Render *re, bool do_all) } /* re->engine becomes zero if user changed active render engine during render */ - if (!persistent_data || !re->engine) { + if (!engine_keep_depsgraph(engine) || !re->engine) { + /* Free depsgraph outside of parts mutex lock, since this locks OpenGL context + * while the the UI drawing might also lock the OpenGL context and parts mutex. */ + BLI_rw_mutex_unlock(&re->partsmutex); + engine_depsgraph_free(engine); + BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_WRITE); + RE_engine_free(engine); re->engine = NULL; } @@ -1023,9 +1111,8 @@ void RE_engine_free_blender_memory(RenderEngine *engine) * * TODO(sergey): Find better solution for this. */ - if (engine->has_grease_pencil) { + if (engine->has_grease_pencil || engine_keep_depsgraph(engine)) { return; } - DEG_graph_free(engine->depsgraph); - engine->depsgraph = NULL; + engine_depsgraph_free(engine); } diff --git a/source/blender/render/intern/pipeline.c b/source/blender/render/intern/pipeline.c index 92bec9c6fd4..5a2ac6ed348 100644 --- a/source/blender/render/intern/pipeline.c +++ b/source/blender/render/intern/pipeline.c @@ -662,17 +662,6 @@ void RE_FreeAllRender(void) #endif } -void RE_FreeAllPersistentData(void) -{ - Render *re; - for (re = RenderGlobal.renderlist.first; re != NULL; re = re->next) { - if ((re->r.mode & R_PERSISTENT_DATA) != 0 && re->engine != NULL) { - RE_engine_free(re->engine); - re->engine = NULL; - } - } -} - /* on file load, free all re */ void RE_FreeAllRenderResults(void) { @@ -687,19 +676,39 @@ void RE_FreeAllRenderResults(void) } } -void RE_FreePersistentData(void) +void RE_FreeAllPersistentData(void) { Render *re; + for (re = RenderGlobal.renderlist.first; re != NULL; re = re->next) { + if (re->engine != NULL) { + BLI_assert(!(re->engine->flag & RE_ENGINE_RENDERING)); + RE_engine_free(re->engine); + re->engine = NULL; + } + } +} - /* render engines can be kept around for quick re-render, this clears all */ - for (re = RenderGlobal.renderlist.first; re; re = re->next) { - if (re->engine) { - /* if engine is currently rendering, just tag it to be freed when render is finished */ - if (!(re->engine->flag & RE_ENGINE_RENDERING)) { - RE_engine_free(re->engine); - } +static void re_free_persistent_data(Render *re) +{ + /* If engine is currently rendering, just wait for it to be freed when it finishes rendering. */ + if (re->engine && !(re->engine->flag & RE_ENGINE_RENDERING)) { + RE_engine_free(re->engine); + re->engine = NULL; + } +} - re->engine = NULL; +void RE_FreePersistentData(const Scene *scene) +{ + /* Render engines can be kept around for quick re-render, this clears all or one scene. */ + if (scene) { + Render *re = RE_GetSceneRender(scene); + if (re) { + re_free_persistent_data(re); + } + } + else { + for (Render *re = RenderGlobal.renderlist.first; re; re = re->next) { + re_free_persistent_data(re); } } } @@ -2669,13 +2678,17 @@ void RE_PreviewRender(Render *re, Main *bmain, Scene *sce) void RE_CleanAfterRender(Render *re) { - /* Destroy the opengl context in the correct thread. */ - RE_gl_context_destroy(re); + if (re->engine && !RE_engine_use_persistent_data(re->engine)) { + RE_engine_free(re->engine); + re->engine = NULL; + } if (re->pipeline_depsgraph != NULL) { DEG_graph_free(re->pipeline_depsgraph); + re->pipeline_depsgraph = NULL; + re->pipeline_scene_eval = NULL; } - re->pipeline_depsgraph = NULL; - re->pipeline_scene_eval = NULL; + /* Destroy the opengl context in the correct thread. */ + RE_gl_context_destroy(re); } /* note; repeated win/disprect calc... solve that nicer, also in compo */ |