Render: faster animation and re-rendering with Persistent Data

For Cycles, when enabling the Persistent Data option, the full render data
will be preserved from frame-to-frame in animation renders and between
re-renders of the scene. This means that any modifier evaluation, BVH
building, OpenGL vertex buffer uploads, etc, can be done only once for
unchanged objects. This comes at an increased memory cost.

Previously there option was named Persistent Images and had a more limited
impact on render time and memory.

When using multiple view layers, only data from a single view layer is
preserved to keep memory usage somewhat under control. However objects
shared between view layers are preserved, and so this can speedup such
renders as well, even single frame renders.

For Eevee and Workbench this option is not available, however these engines
will now always reuse the depsgraph for animation and multiple view layers.
This can significantly speed up rendering.

These engines do not support sharing the depsgraph between re-renders, due
to technical issues regarding OpenGL contexts. Support for this could be added
if those are solved, see the code comments for details.
This commit is contained in:
Brecht Van Lommel 2021-04-04 23:51:24 +02:00
parent 3fa580866e
commit 50782df425
Notes: blender-bot 2023-02-14 07:39:44 +01:00
Referenced by commit 610c0ecc3b, Fix T88204 EEVEE: Animated world light doesnt work during render
Referenced by issue #97625, Regression: Rendering hair instances size in animation bug with animated emitter object scale
Referenced by issue #89040, Cycles renders only two frames of animation
Referenced by issue #88216, persistent data causes collection instance animation to not work properly
Referenced by issue #88204, EEVEE - Animated world light doesnt work during render
Referenced by issue #88210, Image sequence texture don´t update with persistent data
Referenced by issue #88093, Persistent data: Particles/Hair don't render
Referenced by issue #88099, No motion blur on skinned mesh with persistent data enabled
Referenced by issue #87701, Failed assert when generating scene preview
Referenced by issue #87534, Assert BLI_thread_is_main while rendering via a script
Referenced by issue #87464, EEVEE Animation crashes with Motion Blur and Displacement modifier
Referenced by issue #87291, Assert on exit (related to persistent data)
Referenced by issue #87283, 2.93 motion blur breaks persistent data
17 changed files with 229 additions and 125 deletions

View File

@ -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):

View File

@ -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)

View File

@ -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");

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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);
/* 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.
*/
void DEG_ids_check_recalc(struct Main *bmain,
struct Depsgraph *depsgraph,
struct Scene *scene,
struct ViewLayer *view_layer,
bool time);
/* 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 */

View File

@ -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,

View File

@ -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];

View File

@ -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

View File

@ -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;

View File

@ -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,

View File

@ -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 */

View File

@ -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);

View File

@ -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);

View File

@ -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;
engine->depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_RENDER);
DEG_debug_name_set(engine->depsgraph, "RENDER");
/* 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);
}
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);
}

View File

@ -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,23 +676,43 @@ void RE_FreeAllRenderResults(void)
}
}
void RE_FreePersistentData(void)
void RE_FreeAllPersistentData(void)
{
Render *re;
/* 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);
}
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;
}
}
}
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;
}
}
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);
}
}
}
/* ********* initialize state ******** */
/* clear full sample and tile flags if needed */
@ -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 */