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:
Diffstat (limited to 'source/blender/depsgraph/intern/eval')
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc544
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc101
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h55
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.cc49
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.h58
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.cc61
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.h48
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc182
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.h59
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_pose.cc28
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_pose.h37
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.cc82
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.h58
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.cc58
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.h47
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.cc72
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.h49
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.cc64
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.h47
19 files changed, 1158 insertions, 541 deletions
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
index 8a33453b923..3a2cf35f4d5 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
@@ -21,7 +21,7 @@
* \ingroup depsgraph
*/
-/* Enable special; trickery to treat nested owned IDs (such as nodetree of
+/* Enable special trickery to treat nested owned IDs (such as nodetree of
* material) to be handled in same way as "real" data-blocks, even tho some
* internal BKE routines doesn't treat them like that.
*
@@ -95,6 +95,7 @@ extern "C" {
#include "intern/depsgraph.h"
#include "intern/builder/deg_builder.h"
#include "intern/builder/deg_builder_nodes.h"
+#include "intern/eval/deg_eval_runtime_backup.h"
#include "intern/node/deg_node.h"
#include "intern/node/deg_node_id.h"
@@ -945,545 +946,6 @@ ID *deg_expand_copy_on_write_datablock(const Depsgraph *depsgraph,
return deg_expand_copy_on_write_datablock(depsgraph, id_node, node_builder, create_placeholders);
}
-namespace {
-
-/* Backup of sequencer strips runtime data. */
-
-/* Backup of a single strip. */
-class SequenceBackup {
- public:
- SequenceBackup()
- {
- reset();
- }
-
- inline void reset()
- {
- scene_sound = NULL;
- }
-
- void init_from_sequence(Sequence *sequence)
- {
- scene_sound = sequence->scene_sound;
-
- sequence->scene_sound = NULL;
- }
-
- void restore_to_sequence(Sequence *sequence)
- {
- sequence->scene_sound = scene_sound;
- reset();
- }
-
- inline bool isEmpty() const
- {
- return (scene_sound == NULL);
- }
-
- void *scene_sound;
-};
-
-class SequencerBackup {
- public:
- SequencerBackup();
-
- void init_from_scene(Scene *scene);
- void restore_to_scene(Scene *scene);
-
- typedef map<Sequence *, SequenceBackup> SequencesBackupMap;
- SequencesBackupMap sequences_backup;
-};
-
-SequencerBackup::SequencerBackup()
-{
-}
-
-void SequencerBackup::init_from_scene(Scene *scene)
-{
- Sequence *sequence;
- SEQ_BEGIN (scene->ed, sequence) {
- SequenceBackup sequence_backup;
- sequence_backup.init_from_sequence(sequence);
- if (!sequence_backup.isEmpty()) {
- sequences_backup.insert(make_pair(sequence->orig_sequence, sequence_backup));
- }
- }
- SEQ_END;
-}
-
-void SequencerBackup::restore_to_scene(Scene *scene)
-{
- Sequence *sequence;
- SEQ_BEGIN (scene->ed, sequence) {
- SequencesBackupMap::iterator it = sequences_backup.find(sequence->orig_sequence);
- if (it == sequences_backup.end()) {
- continue;
- }
- SequenceBackup &sequence_backup = it->second;
- sequence_backup.restore_to_sequence(sequence);
- }
- SEQ_END;
- /* Cleanup audio while the scene is still known. */
- for (SequencesBackupMap::value_type &it : sequences_backup) {
- SequenceBackup &sequence_backup = it.second;
- if (sequence_backup.scene_sound != NULL) {
- BKE_sound_remove_scene_sound(scene, sequence_backup.scene_sound);
- }
- }
-}
-
-/* Backup of scene runtime data. */
-
-class SceneBackup {
- public:
- SceneBackup();
-
- void reset();
-
- void init_from_scene(Scene *scene);
- void restore_to_scene(Scene *scene);
-
- /* Sound/audio related pointers of the scene itself.
- *
- * NOTE: Scene can not disappear after relations update, because otherwise the entire dependency
- * graph will be gone. This means we don't need to compare original scene pointer, or worry about
- * freeing those if they cant' be restored: we just copy them over to a new scene. */
- void *sound_scene;
- void *playback_handle;
- void *sound_scrub_handle;
- void *speaker_handles;
- float rigidbody_last_time;
-
- SequencerBackup sequencer_backup;
-};
-
-SceneBackup::SceneBackup()
-{
- reset();
-}
-
-void SceneBackup::reset()
-{
- sound_scene = NULL;
- playback_handle = NULL;
- sound_scrub_handle = NULL;
- speaker_handles = NULL;
- rigidbody_last_time = -1;
-}
-
-void SceneBackup::init_from_scene(Scene *scene)
-{
- sound_scene = scene->sound_scene;
- playback_handle = scene->playback_handle;
- sound_scrub_handle = scene->sound_scrub_handle;
- speaker_handles = scene->speaker_handles;
-
- if (scene->rigidbody_world != NULL) {
- rigidbody_last_time = scene->rigidbody_world->ltime;
- }
-
- /* Clear pointers stored in the scene, so they are not freed when copied-on-written datablock
- * is freed for re-allocation. */
- scene->sound_scene = NULL;
- scene->playback_handle = NULL;
- scene->sound_scrub_handle = NULL;
- scene->speaker_handles = NULL;
-
- sequencer_backup.init_from_scene(scene);
-}
-
-void SceneBackup::restore_to_scene(Scene *scene)
-{
- scene->sound_scene = sound_scene;
- scene->playback_handle = playback_handle;
- scene->sound_scrub_handle = sound_scrub_handle;
- scene->speaker_handles = speaker_handles;
-
- if (scene->rigidbody_world != NULL) {
- scene->rigidbody_world->ltime = rigidbody_last_time;
- }
-
- sequencer_backup.restore_to_scene(scene);
-
- reset();
-}
-
-/* Backup of sound datablocks runtime data. */
-
-class SoundBackup {
- public:
- SoundBackup();
-
- void reset();
-
- void init_from_sound(bSound *sound);
- void restore_to_sound(bSound *sound);
-
- void *cache;
- void *waveform;
- void *playback_handle;
-};
-
-SoundBackup::SoundBackup()
-{
- reset();
-}
-
-void SoundBackup::reset()
-{
- cache = NULL;
- waveform = NULL;
- playback_handle = NULL;
-}
-
-void SoundBackup::init_from_sound(bSound *sound)
-{
- cache = sound->cache;
- waveform = sound->waveform;
- playback_handle = sound->playback_handle;
-
- sound->cache = NULL;
- sound->waveform = NULL;
- sound->playback_handle = NULL;
-}
-
-void SoundBackup::restore_to_sound(bSound *sound)
-{
- sound->cache = cache;
- sound->waveform = waveform;
- sound->playback_handle = playback_handle;
-
- reset();
-}
-
-/* Identifier used to match modifiers to backup/restore their runtime data.
- * Identification is happening using original modifier data pointer and the
- * modifier type.
- * It is not enough to only pointer, since it's possible to have a situation
- * when modifier is removed and a new one added, and due to memory allocation
- * policy they might have same pointer.
- * By adding type into matching we are at least ensuring that modifier will not
- * try to interpret runtime data created by another modifier type. */
-class ModifierDataBackupID {
- public:
- ModifierDataBackupID() : ModifierDataBackupID(NULL, eModifierType_None)
- {
- }
-
- ModifierDataBackupID(ModifierData *modifier_data, ModifierType type)
- : modifier_data(modifier_data), type(type)
- {
- }
-
- bool operator<(const ModifierDataBackupID &other) const
- {
- if (modifier_data < other.modifier_data) {
- return true;
- }
- if (modifier_data == other.modifier_data) {
- return static_cast<int>(type) < static_cast<int>(other.type);
- }
- return false;
- }
-
- ModifierData *modifier_data;
- ModifierType type;
-};
-
-/* Storage for backed up runtime modifier data. */
-typedef map<ModifierDataBackupID, void *> ModifierRuntimeDataBackup;
-
-/* Storage for backed up pose channel runtime data. */
-typedef map<bPoseChannel *, bPoseChannel_Runtime> PoseChannelRuntimeDataBackup;
-
-class ObjectRuntimeBackup {
- public:
- ObjectRuntimeBackup() : base_flag(0), base_local_view_bits(0)
- {
- /* TODO(sergey): Use something like BKE_object_runtime_reset(). */
- memset(&runtime, 0, sizeof(runtime));
- }
-
- /* Make a backup of object's evaluation runtime data, additionally
- * make object to be safe for free without invalidating backed up
- * pointers. */
- void init_from_object(Object *object);
- void backup_modifier_runtime_data(Object *object);
- void backup_pose_channel_runtime_data(Object *object);
-
- /* Restore all fields to the given object. */
- void restore_to_object(Object *object);
- /* NOTE: Will free all runtime data which has not been restored. */
- void restore_modifier_runtime_data(Object *object);
- void restore_pose_channel_runtime_data(Object *object);
-
- Object_Runtime runtime;
- short base_flag;
- unsigned short base_local_view_bits;
- ModifierRuntimeDataBackup modifier_runtime_data;
- PoseChannelRuntimeDataBackup pose_channel_runtime_data;
-};
-
-void ObjectRuntimeBackup::init_from_object(Object *object)
-{
- /* Store evaluated mesh and curve_cache, and make sure we don't free it. */
- Mesh *mesh_eval = object->runtime.mesh_eval;
- runtime = object->runtime;
- BKE_object_runtime_reset(object);
- /* Keep bbox (for now at least). */
- object->runtime.bb = runtime.bb;
- /* Object update will override actual object->data to an evaluated version.
- * Need to make sure we don't have data set to evaluated one before free
- * anything. */
- if (mesh_eval != NULL && object->data == mesh_eval) {
- object->data = runtime.mesh_orig;
- }
- /* Make a backup of base flags. */
- base_flag = object->base_flag;
- base_local_view_bits = object->base_local_view_bits;
- /* Backup tuntime data of all modifiers. */
- backup_modifier_runtime_data(object);
- /* Backup runtime data of all pose channels. */
- backup_pose_channel_runtime_data(object);
-}
-
-inline ModifierDataBackupID create_modifier_data_id(const ModifierData *modifier_data)
-{
- return ModifierDataBackupID(modifier_data->orig_modifier_data,
- static_cast<ModifierType>(modifier_data->type));
-}
-
-void ObjectRuntimeBackup::backup_modifier_runtime_data(Object *object)
-{
- LISTBASE_FOREACH (ModifierData *, modifier_data, &object->modifiers) {
- if (modifier_data->runtime == NULL) {
- continue;
- }
- BLI_assert(modifier_data->orig_modifier_data != NULL);
- ModifierDataBackupID modifier_data_id = create_modifier_data_id(modifier_data);
- modifier_runtime_data.insert(make_pair(modifier_data_id, modifier_data->runtime));
- modifier_data->runtime = NULL;
- }
-}
-
-void ObjectRuntimeBackup::backup_pose_channel_runtime_data(Object *object)
-{
- if (object->pose != NULL) {
- LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
- /* This is NULL in Edit mode. */
- if (pchan->orig_pchan != NULL) {
- pose_channel_runtime_data[pchan->orig_pchan] = pchan->runtime;
- BKE_pose_channel_runtime_reset(&pchan->runtime);
- }
- }
- }
-}
-
-void ObjectRuntimeBackup::restore_to_object(Object *object)
-{
- Mesh *mesh_orig = object->runtime.mesh_orig;
- BoundBox *bb = object->runtime.bb;
- object->runtime = runtime;
- object->runtime.mesh_orig = mesh_orig;
- object->runtime.bb = bb;
- if (object->type == OB_MESH && object->runtime.mesh_eval != NULL) {
- if (object->id.recalc & ID_RECALC_GEOMETRY) {
- /* If geometry is tagged for update it means, that part of
- * evaluated mesh are not valid anymore. In this case we can not
- * have any "persistent" pointers to point to an invalid data.
- *
- * We restore object's data datablock to an original copy of
- * that datablock. */
- object->data = mesh_orig;
-
- /* After that, immediately free the invalidated caches. */
- BKE_object_free_derived_caches(object);
- }
- else {
- Mesh *mesh_eval = object->runtime.mesh_eval;
- /* Do same thing as object update: override actual object data
- * pointer with evaluated datablock. */
- object->data = mesh_eval;
- /* Evaluated mesh simply copied edit_mesh pointer from
- * original mesh during update, need to make sure no dead
- * pointers are left behind. */
- mesh_eval->edit_mesh = mesh_orig->edit_mesh;
- }
- }
- object->base_flag = base_flag;
- object->base_local_view_bits = base_local_view_bits;
- /* Restore modifier's runtime data.
- * NOTE: Data of unused modifiers will be freed there. */
- restore_modifier_runtime_data(object);
- restore_pose_channel_runtime_data(object);
-}
-
-void ObjectRuntimeBackup::restore_modifier_runtime_data(Object *object)
-{
- LISTBASE_FOREACH (ModifierData *, modifier_data, &object->modifiers) {
- BLI_assert(modifier_data->orig_modifier_data != NULL);
- ModifierDataBackupID modifier_data_id = create_modifier_data_id(modifier_data);
- ModifierRuntimeDataBackup::iterator runtime_data_iterator = modifier_runtime_data.find(
- modifier_data_id);
- if (runtime_data_iterator != modifier_runtime_data.end()) {
- modifier_data->runtime = runtime_data_iterator->second;
- runtime_data_iterator->second = NULL;
- }
- }
- for (ModifierRuntimeDataBackup::value_type value : modifier_runtime_data) {
- const ModifierDataBackupID modifier_data_id = value.first;
- void *runtime = value.second;
- if (value.second == NULL) {
- continue;
- }
- const ModifierTypeInfo *modifier_type_info = modifierType_getInfo(modifier_data_id.type);
- BLI_assert(modifier_type_info != NULL);
- modifier_type_info->freeRuntimeData(runtime);
- }
-}
-
-void ObjectRuntimeBackup::restore_pose_channel_runtime_data(Object *object)
-{
- if (object->pose != NULL) {
- LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
- /* This is NULL in Edit mode. */
- if (pchan->orig_pchan != NULL) {
- PoseChannelRuntimeDataBackup::iterator runtime_data_iterator =
- pose_channel_runtime_data.find(pchan->orig_pchan);
- if (runtime_data_iterator != pose_channel_runtime_data.end()) {
- pchan->runtime = runtime_data_iterator->second;
- pose_channel_runtime_data.erase(runtime_data_iterator);
- }
- }
- }
- }
- for (PoseChannelRuntimeDataBackup::value_type &value : pose_channel_runtime_data) {
- BKE_pose_channel_runtime_free(&value.second);
- }
-}
-
-/* Backup of movie clip runtime data. */
-
-class MovieClipBackup {
- public:
- MovieClipBackup();
-
- void reset();
-
- void init_from_movieclip(MovieClip *movieclip);
- void restore_to_movieclip(MovieClip *movieclip);
-
- struct anim *anim;
- struct MovieClipCache *cache;
-};
-
-MovieClipBackup::MovieClipBackup()
-{
- reset();
-}
-
-void MovieClipBackup::reset()
-{
- anim = NULL;
- cache = NULL;
-}
-
-void MovieClipBackup::init_from_movieclip(MovieClip *movieclip)
-{
- anim = movieclip->anim;
- cache = movieclip->cache;
- /* Clear pointers stored in the movie clip, so they are not freed when copied-on-written
- * datablock is freed for re-allocation. */
- movieclip->anim = NULL;
- movieclip->cache = NULL;
-}
-
-void MovieClipBackup::restore_to_movieclip(MovieClip *movieclip)
-{
- movieclip->anim = anim;
- movieclip->cache = cache;
-
- reset();
-}
-
-class RuntimeBackup {
- public:
- RuntimeBackup() : drawdata_ptr(NULL)
- {
- drawdata_backup.first = drawdata_backup.last = NULL;
- }
-
- /* NOTE: Will reset all runbtime fields which has been backed up to NULL. */
- void init_from_id(ID *id);
-
- /* Restore fields to the given ID. */
- void restore_to_id(ID *id);
-
- SceneBackup scene_backup;
- SoundBackup sound_backup;
- ObjectRuntimeBackup object_backup;
- DrawDataList drawdata_backup;
- DrawDataList *drawdata_ptr;
- MovieClipBackup movieclip_backup;
-};
-
-void RuntimeBackup::init_from_id(ID *id)
-{
- if (!check_datablock_expanded(id)) {
- return;
- }
- const ID_Type id_type = GS(id->name);
- switch (id_type) {
- case ID_OB:
- object_backup.init_from_object(reinterpret_cast<Object *>(id));
- break;
- case ID_SCE:
- scene_backup.init_from_scene(reinterpret_cast<Scene *>(id));
- break;
- case ID_SO:
- sound_backup.init_from_sound(reinterpret_cast<bSound *>(id));
- break;
- case ID_MC:
- movieclip_backup.init_from_movieclip(reinterpret_cast<MovieClip *>(id));
- break;
- default:
- break;
- }
- /* Note that we never free GPU draw data from here since that's not
- * safe for threading and draw data is likely to be re-used. */
- drawdata_ptr = DRW_drawdatalist_from_id(id);
- if (drawdata_ptr != NULL) {
- drawdata_backup = *drawdata_ptr;
- drawdata_ptr->first = drawdata_ptr->last = NULL;
- }
-}
-
-void RuntimeBackup::restore_to_id(ID *id)
-{
- const ID_Type id_type = GS(id->name);
- switch (id_type) {
- case ID_OB:
- object_backup.restore_to_object(reinterpret_cast<Object *>(id));
- break;
- case ID_SCE:
- scene_backup.restore_to_scene(reinterpret_cast<Scene *>(id));
- break;
- case ID_SO:
- sound_backup.restore_to_sound(reinterpret_cast<bSound *>(id));
- break;
- case ID_MC:
- movieclip_backup.restore_to_movieclip(reinterpret_cast<MovieClip *>(id));
- break;
- default:
- break;
- }
- if (drawdata_ptr != NULL) {
- *drawdata_ptr = drawdata_backup;
- }
-}
-
-} // namespace
-
ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, const IDNode *id_node)
{
const ID *id_orig = id_node->id_orig;
@@ -1492,7 +954,7 @@ ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, const IDNode
if (!deg_copy_on_write_is_needed(id_orig)) {
return id_cow;
}
- RuntimeBackup backup;
+ RuntimeBackup backup(depsgraph);
backup.init_from_id(id_cow);
deg_free_copy_on_write_datablock(id_cow);
deg_expand_copy_on_write_datablock(depsgraph, id_node);
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc
new file mode 100644
index 00000000000..88390ab412f
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc
@@ -0,0 +1,101 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#include "intern/eval/deg_eval_runtime_backup.h"
+
+#include "intern/eval/deg_eval_copy_on_write.h"
+
+#include "BLI_utildefines.h"
+
+#include "DRW_engine.h"
+
+namespace DEG {
+
+RuntimeBackup::RuntimeBackup(const Depsgraph *depsgraph)
+ : scene_backup(depsgraph),
+ sound_backup(depsgraph),
+ object_backup(depsgraph),
+ drawdata_ptr(NULL),
+ movieclip_backup(depsgraph)
+{
+ drawdata_backup.first = drawdata_backup.last = NULL;
+}
+
+void RuntimeBackup::init_from_id(ID *id)
+{
+ if (!deg_copy_on_write_is_expanded(id)) {
+ return;
+ }
+
+ const ID_Type id_type = GS(id->name);
+ switch (id_type) {
+ case ID_OB:
+ object_backup.init_from_object(reinterpret_cast<Object *>(id));
+ break;
+ case ID_SCE:
+ scene_backup.init_from_scene(reinterpret_cast<Scene *>(id));
+ break;
+ case ID_SO:
+ sound_backup.init_from_sound(reinterpret_cast<bSound *>(id));
+ break;
+ case ID_MC:
+ movieclip_backup.init_from_movieclip(reinterpret_cast<MovieClip *>(id));
+ break;
+ default:
+ break;
+ }
+
+ /* Note that we never free GPU draw data from here since that's not
+ * safe for threading and draw data is likely to be re-used. */
+ drawdata_ptr = DRW_drawdatalist_from_id(id);
+ if (drawdata_ptr != NULL) {
+ drawdata_backup = *drawdata_ptr;
+ drawdata_ptr->first = drawdata_ptr->last = NULL;
+ }
+}
+
+void RuntimeBackup::restore_to_id(ID *id)
+{
+ const ID_Type id_type = GS(id->name);
+ switch (id_type) {
+ case ID_OB:
+ object_backup.restore_to_object(reinterpret_cast<Object *>(id));
+ break;
+ case ID_SCE:
+ scene_backup.restore_to_scene(reinterpret_cast<Scene *>(id));
+ break;
+ case ID_SO:
+ sound_backup.restore_to_sound(reinterpret_cast<bSound *>(id));
+ break;
+ case ID_MC:
+ movieclip_backup.restore_to_movieclip(reinterpret_cast<MovieClip *>(id));
+ break;
+ default:
+ break;
+ }
+ if (drawdata_ptr != NULL) {
+ *drawdata_ptr = drawdata_backup;
+ }
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h
new file mode 100644
index 00000000000..31ae3164e37
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h
@@ -0,0 +1,55 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+#include "DNA_ID.h"
+
+#include "intern/eval/deg_eval_runtime_backup_movieclip.h"
+#include "intern/eval/deg_eval_runtime_backup_object.h"
+#include "intern/eval/deg_eval_runtime_backup_scene.h"
+#include "intern/eval/deg_eval_runtime_backup_sound.h"
+
+namespace DEG {
+
+struct Depsgraph;
+
+class RuntimeBackup {
+ public:
+ explicit RuntimeBackup(const Depsgraph *depsgraph);
+
+ /* NOTE: Will reset all runtime fields which has been backed up to NULL. */
+ void init_from_id(ID *id);
+
+ /* Restore fields to the given ID. */
+ void restore_to_id(ID *id);
+
+ SceneBackup scene_backup;
+ SoundBackup sound_backup;
+ ObjectRuntimeBackup object_backup;
+ DrawDataList drawdata_backup;
+ DrawDataList *drawdata_ptr;
+ MovieClipBackup movieclip_backup;
+};
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.cc
new file mode 100644
index 00000000000..c5744533083
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.cc
@@ -0,0 +1,49 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#include "intern/eval/deg_eval_runtime_backup_modifier.h"
+
+namespace DEG {
+
+ModifierDataBackupID::ModifierDataBackupID(const Depsgraph * /*depsgraph*/)
+ : ModifierDataBackupID(NULL, eModifierType_None)
+{
+}
+
+ModifierDataBackupID::ModifierDataBackupID(ModifierData *modifier_data, ModifierType type)
+ : modifier_data(modifier_data), type(type)
+{
+}
+
+bool ModifierDataBackupID::operator<(const ModifierDataBackupID &other) const
+{
+ if (modifier_data < other.modifier_data) {
+ return true;
+ }
+ if (modifier_data == other.modifier_data) {
+ return static_cast<int>(type) < static_cast<int>(other.type);
+ }
+ return false;
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.h
new file mode 100644
index 00000000000..4b3d46126f3
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.h
@@ -0,0 +1,58 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+#include "BKE_modifier.h"
+
+#include "intern/depsgraph_type.h"
+
+struct ModifierData;
+
+namespace DEG {
+
+struct Depsgraph;
+
+/* Identifier used to match modifiers to backup/restore their runtime data.
+ * Identification is happening using original modifier data pointer and the
+ * modifier type.
+ * It is not enough to only pointer, since it's possible to have a situation
+ * when modifier is removed and a new one added, and due to memory allocation
+ * policy they might have same pointer.
+ * By adding type into matching we are at least ensuring that modifier will not
+ * try to interpret runtime data created by another modifier type. */
+class ModifierDataBackupID {
+ public:
+ ModifierDataBackupID(const Depsgraph *depsgraph);
+ ModifierDataBackupID(ModifierData *modifier_data, ModifierType type);
+
+ bool operator<(const ModifierDataBackupID &other) const;
+
+ ModifierData *modifier_data;
+ ModifierType type;
+};
+
+/* Storage for backed up runtime modifier data. */
+typedef map<ModifierDataBackupID, void *> ModifierRuntimeDataBackup;
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.cc
new file mode 100644
index 00000000000..54838475bbf
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.cc
@@ -0,0 +1,61 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#include "intern/eval/deg_eval_runtime_backup_movieclip.h"
+
+#include "DNA_movieclip_types.h"
+
+#include "BLI_utildefines.h"
+
+namespace DEG {
+
+MovieClipBackup::MovieClipBackup(const Depsgraph * /*depsgraph*/)
+{
+ reset();
+}
+
+void MovieClipBackup::reset()
+{
+ anim = NULL;
+ cache = NULL;
+}
+
+void MovieClipBackup::init_from_movieclip(MovieClip *movieclip)
+{
+ anim = movieclip->anim;
+ cache = movieclip->cache;
+ /* Clear pointers stored in the movie clip, so they are not freed when copied-on-written
+ * datablock is freed for re-allocation. */
+ movieclip->anim = NULL;
+ movieclip->cache = NULL;
+}
+
+void MovieClipBackup::restore_to_movieclip(MovieClip *movieclip)
+{
+ movieclip->anim = anim;
+ movieclip->cache = cache;
+
+ reset();
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.h
new file mode 100644
index 00000000000..a9d528a254c
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.h
@@ -0,0 +1,48 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+struct anim;
+struct MovieClip;
+struct MovieClipCache;
+
+namespace DEG {
+
+struct Depsgraph;
+
+/* Backup of movie clip runtime data. */
+class MovieClipBackup {
+ public:
+ MovieClipBackup(const Depsgraph *depsgraph);
+
+ void reset();
+
+ void init_from_movieclip(MovieClip *movieclip);
+ void restore_to_movieclip(MovieClip *movieclip);
+
+ struct anim *anim;
+ struct MovieClipCache *cache;
+};
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc
new file mode 100644
index 00000000000..a6a042f3e7b
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc
@@ -0,0 +1,182 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#include "intern/eval/deg_eval_runtime_backup_object.h"
+
+#include <cstring>
+
+#include "DNA_mesh_types.h"
+
+#include "BLI_listbase.h"
+
+#include "BKE_action.h"
+#include "BKE_object.h"
+
+namespace DEG {
+
+ObjectRuntimeBackup::ObjectRuntimeBackup(const Depsgraph * /*depsgraph*/)
+ : base_flag(0), base_local_view_bits(0)
+{
+ /* TODO(sergey): Use something like BKE_object_runtime_reset(). */
+ memset(&runtime, 0, sizeof(runtime));
+}
+
+void ObjectRuntimeBackup::init_from_object(Object *object)
+{
+ /* Store evaluated mesh and curve_cache, and make sure we don't free it. */
+ Mesh *mesh_eval = object->runtime.mesh_eval;
+ runtime = object->runtime;
+ BKE_object_runtime_reset(object);
+ /* Keep bbox (for now at least). */
+ object->runtime.bb = runtime.bb;
+ /* Object update will override actual object->data to an evaluated version.
+ * Need to make sure we don't have data set to evaluated one before free
+ * anything. */
+ if (mesh_eval != NULL && object->data == mesh_eval) {
+ object->data = runtime.mesh_orig;
+ }
+ /* Make a backup of base flags. */
+ base_flag = object->base_flag;
+ base_local_view_bits = object->base_local_view_bits;
+ /* Backup tuntime data of all modifiers. */
+ backup_modifier_runtime_data(object);
+ /* Backup runtime data of all pose channels. */
+ backup_pose_channel_runtime_data(object);
+}
+
+inline ModifierDataBackupID create_modifier_data_id(const ModifierData *modifier_data)
+{
+ return ModifierDataBackupID(modifier_data->orig_modifier_data,
+ static_cast<ModifierType>(modifier_data->type));
+}
+
+void ObjectRuntimeBackup::backup_modifier_runtime_data(Object *object)
+{
+ LISTBASE_FOREACH (ModifierData *, modifier_data, &object->modifiers) {
+ if (modifier_data->runtime == NULL) {
+ continue;
+ }
+ BLI_assert(modifier_data->orig_modifier_data != NULL);
+ ModifierDataBackupID modifier_data_id = create_modifier_data_id(modifier_data);
+ modifier_runtime_data.insert(make_pair(modifier_data_id, modifier_data->runtime));
+ modifier_data->runtime = NULL;
+ }
+}
+
+void ObjectRuntimeBackup::backup_pose_channel_runtime_data(Object *object)
+{
+ if (object->pose != NULL) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
+ /* This is NULL in Edit mode. */
+ if (pchan->orig_pchan != NULL) {
+ pose_channel_runtime_data[pchan->orig_pchan] = pchan->runtime;
+ BKE_pose_channel_runtime_reset(&pchan->runtime);
+ }
+ }
+ }
+}
+
+void ObjectRuntimeBackup::restore_to_object(Object *object)
+{
+ Mesh *mesh_orig = object->runtime.mesh_orig;
+ BoundBox *bb = object->runtime.bb;
+ object->runtime = runtime;
+ object->runtime.mesh_orig = mesh_orig;
+ object->runtime.bb = bb;
+ if (object->type == OB_MESH && object->runtime.mesh_eval != NULL) {
+ if (object->id.recalc & ID_RECALC_GEOMETRY) {
+ /* If geometry is tagged for update it means, that part of
+ * evaluated mesh are not valid anymore. In this case we can not
+ * have any "persistent" pointers to point to an invalid data.
+ *
+ * We restore object's data datablock to an original copy of
+ * that datablock. */
+ object->data = mesh_orig;
+
+ /* After that, immediately free the invalidated caches. */
+ BKE_object_free_derived_caches(object);
+ }
+ else {
+ Mesh *mesh_eval = object->runtime.mesh_eval;
+ /* Do same thing as object update: override actual object data
+ * pointer with evaluated datablock. */
+ object->data = mesh_eval;
+ /* Evaluated mesh simply copied edit_mesh pointer from
+ * original mesh during update, need to make sure no dead
+ * pointers are left behind. */
+ mesh_eval->edit_mesh = mesh_orig->edit_mesh;
+ }
+ }
+ object->base_flag = base_flag;
+ object->base_local_view_bits = base_local_view_bits;
+ /* Restore modifier's runtime data.
+ * NOTE: Data of unused modifiers will be freed there. */
+ restore_modifier_runtime_data(object);
+ restore_pose_channel_runtime_data(object);
+}
+
+void ObjectRuntimeBackup::restore_modifier_runtime_data(Object *object)
+{
+ LISTBASE_FOREACH (ModifierData *, modifier_data, &object->modifiers) {
+ BLI_assert(modifier_data->orig_modifier_data != NULL);
+ ModifierDataBackupID modifier_data_id = create_modifier_data_id(modifier_data);
+ ModifierRuntimeDataBackup::iterator runtime_data_iterator = modifier_runtime_data.find(
+ modifier_data_id);
+ if (runtime_data_iterator != modifier_runtime_data.end()) {
+ modifier_data->runtime = runtime_data_iterator->second;
+ runtime_data_iterator->second = NULL;
+ }
+ }
+ for (ModifierRuntimeDataBackup::value_type value : modifier_runtime_data) {
+ const ModifierDataBackupID modifier_data_id = value.first;
+ void *runtime = value.second;
+ if (value.second == NULL) {
+ continue;
+ }
+ const ModifierTypeInfo *modifier_type_info = modifierType_getInfo(modifier_data_id.type);
+ BLI_assert(modifier_type_info != NULL);
+ modifier_type_info->freeRuntimeData(runtime);
+ }
+}
+
+void ObjectRuntimeBackup::restore_pose_channel_runtime_data(Object *object)
+{
+ if (object->pose != NULL) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
+ /* This is NULL in Edit mode. */
+ if (pchan->orig_pchan != NULL) {
+ PoseChannelRuntimeDataBackup::iterator runtime_data_iterator =
+ pose_channel_runtime_data.find(pchan->orig_pchan);
+ if (runtime_data_iterator != pose_channel_runtime_data.end()) {
+ pchan->runtime = runtime_data_iterator->second;
+ pose_channel_runtime_data.erase(runtime_data_iterator);
+ }
+ }
+ }
+ }
+ for (PoseChannelRuntimeDataBackup::value_type &value : pose_channel_runtime_data) {
+ BKE_pose_channel_runtime_free(&value.second);
+ }
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.h
new file mode 100644
index 00000000000..e5c3d6a967a
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.h
@@ -0,0 +1,59 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+#include "DNA_object_types.h"
+
+#include "intern/eval/deg_eval_runtime_backup_modifier.h"
+#include "intern/eval/deg_eval_runtime_backup_pose.h"
+
+struct Object;
+
+namespace DEG {
+
+class ObjectRuntimeBackup {
+ public:
+ ObjectRuntimeBackup(const Depsgraph *depsgraph);
+
+ /* Make a backup of object's evaluation runtime data, additionally
+ * make object to be safe for free without invalidating backed up
+ * pointers. */
+ void init_from_object(Object *object);
+ void backup_modifier_runtime_data(Object *object);
+ void backup_pose_channel_runtime_data(Object *object);
+
+ /* Restore all fields to the given object. */
+ void restore_to_object(Object *object);
+ /* NOTE: Will free all runtime data which has not been restored. */
+ void restore_modifier_runtime_data(Object *object);
+ void restore_pose_channel_runtime_data(Object *object);
+
+ Object_Runtime runtime;
+ short base_flag;
+ unsigned short base_local_view_bits;
+ ModifierRuntimeDataBackup modifier_runtime_data;
+ PoseChannelRuntimeDataBackup pose_channel_runtime_data;
+};
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_pose.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_pose.cc
new file mode 100644
index 00000000000..821cc21f359
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_pose.cc
@@ -0,0 +1,28 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#include "intern/eval/deg_eval_runtime_backup_pose.h"
+
+namespace DEG {
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_pose.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_pose.h
new file mode 100644
index 00000000000..53a2c4c0784
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_pose.h
@@ -0,0 +1,37 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+#include "intern/depsgraph_type.h"
+
+#include "DNA_action_types.h"
+
+struct bPoseChannel;
+
+namespace DEG {
+
+/* Storage for backed up pose channel runtime data. */
+typedef map<bPoseChannel *, bPoseChannel_Runtime> PoseChannelRuntimeDataBackup;
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.cc
new file mode 100644
index 00000000000..a288fb6ab92
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.cc
@@ -0,0 +1,82 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#include "intern/eval/deg_eval_runtime_backup_scene.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_rigidbody_types.h"
+
+namespace DEG {
+
+SceneBackup::SceneBackup(const Depsgraph *depsgraph) : sequencer_backup(depsgraph)
+{
+ reset();
+}
+
+void SceneBackup::reset()
+{
+ sound_scene = NULL;
+ playback_handle = NULL;
+ sound_scrub_handle = NULL;
+ speaker_handles = NULL;
+ rigidbody_last_time = -1;
+}
+
+void SceneBackup::init_from_scene(Scene *scene)
+{
+ sound_scene = scene->sound_scene;
+ playback_handle = scene->playback_handle;
+ sound_scrub_handle = scene->sound_scrub_handle;
+ speaker_handles = scene->speaker_handles;
+
+ if (scene->rigidbody_world != NULL) {
+ rigidbody_last_time = scene->rigidbody_world->ltime;
+ }
+
+ /* Clear pointers stored in the scene, so they are not freed when copied-on-written datablock
+ * is freed for re-allocation. */
+ scene->sound_scene = NULL;
+ scene->playback_handle = NULL;
+ scene->sound_scrub_handle = NULL;
+ scene->speaker_handles = NULL;
+
+ sequencer_backup.init_from_scene(scene);
+}
+
+void SceneBackup::restore_to_scene(Scene *scene)
+{
+ scene->sound_scene = sound_scene;
+ scene->playback_handle = playback_handle;
+ scene->sound_scrub_handle = sound_scrub_handle;
+ scene->speaker_handles = speaker_handles;
+
+ if (scene->rigidbody_world != NULL) {
+ scene->rigidbody_world->ltime = rigidbody_last_time;
+ }
+
+ sequencer_backup.restore_to_scene(scene);
+
+ reset();
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.h
new file mode 100644
index 00000000000..751bc4208d2
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.h
@@ -0,0 +1,58 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+#include "intern/eval/deg_eval_runtime_backup_sequencer.h"
+
+struct Scene;
+
+namespace DEG {
+
+struct Depsgraph;
+
+/* Backup of scene runtime data. */
+class SceneBackup {
+ public:
+ SceneBackup(const Depsgraph *depsgraph);
+
+ void reset();
+
+ void init_from_scene(Scene *scene);
+ void restore_to_scene(Scene *scene);
+
+ /* Sound/audio related pointers of the scene itself.
+ *
+ * NOTE: Scene can not disappear after relations update, because otherwise the entire dependency
+ * graph will be gone. This means we don't need to compare original scene pointer, or worry about
+ * freeing those if they cant' be restored: we just copy them over to a new scene. */
+ void *sound_scene;
+ void *playback_handle;
+ void *sound_scrub_handle;
+ void *speaker_handles;
+ float rigidbody_last_time;
+
+ SequencerBackup sequencer_backup;
+};
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.cc
new file mode 100644
index 00000000000..0150281a4ef
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.cc
@@ -0,0 +1,58 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#include "intern/eval/deg_eval_runtime_backup_sequence.h"
+
+#include "DNA_sequence_types.h"
+
+namespace DEG {
+
+SequenceBackup::SequenceBackup(const Depsgraph * /*depsgraph*/)
+{
+ reset();
+}
+
+void SequenceBackup::reset()
+{
+ scene_sound = NULL;
+}
+
+void SequenceBackup::init_from_sequence(Sequence *sequence)
+{
+ scene_sound = sequence->scene_sound;
+
+ sequence->scene_sound = NULL;
+}
+
+void SequenceBackup::restore_to_sequence(Sequence *sequence)
+{
+ sequence->scene_sound = scene_sound;
+ reset();
+}
+
+bool SequenceBackup::isEmpty() const
+{
+ return (scene_sound == NULL);
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.h
new file mode 100644
index 00000000000..8a762a2785e
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.h
@@ -0,0 +1,47 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+struct Sequence;
+
+namespace DEG {
+
+struct Depsgraph;
+
+/* Backup of a single strip. */
+class SequenceBackup {
+ public:
+ SequenceBackup(const Depsgraph *depsgraph);
+
+ void reset();
+
+ void init_from_sequence(Sequence *sequence);
+ void restore_to_sequence(Sequence *sequence);
+
+ bool isEmpty() const;
+
+ void *scene_sound;
+};
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.cc
new file mode 100644
index 00000000000..08c2697aab3
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.cc
@@ -0,0 +1,72 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#include "intern/eval/deg_eval_runtime_backup_sequencer.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_sequence_types.h"
+
+#include "BKE_sequencer.h"
+#include "BKE_sound.h"
+
+namespace DEG {
+
+SequencerBackup::SequencerBackup(const Depsgraph *depsgraph) : depsgraph(depsgraph)
+{
+}
+
+void SequencerBackup::init_from_scene(Scene *scene)
+{
+ Sequence *sequence;
+ SEQ_BEGIN (scene->ed, sequence) {
+ SequenceBackup sequence_backup(depsgraph);
+ sequence_backup.init_from_sequence(sequence);
+ if (!sequence_backup.isEmpty()) {
+ sequences_backup.insert(make_pair(sequence->orig_sequence, sequence_backup));
+ }
+ }
+ SEQ_END;
+}
+
+void SequencerBackup::restore_to_scene(Scene *scene)
+{
+ Sequence *sequence;
+ SEQ_BEGIN (scene->ed, sequence) {
+ SequencesBackupMap::iterator it = sequences_backup.find(sequence->orig_sequence);
+ if (it == sequences_backup.end()) {
+ continue;
+ }
+ SequenceBackup &sequence_backup = it->second;
+ sequence_backup.restore_to_sequence(sequence);
+ }
+ SEQ_END;
+ /* Cleanup audio while the scene is still known. */
+ for (SequencesBackupMap::value_type &it : sequences_backup) {
+ SequenceBackup &sequence_backup = it.second;
+ if (sequence_backup.scene_sound != NULL) {
+ BKE_sound_remove_scene_sound(scene, sequence_backup.scene_sound);
+ }
+ }
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.h
new file mode 100644
index 00000000000..57b533a1b84
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.h
@@ -0,0 +1,49 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+#include "intern/eval/deg_eval_runtime_backup_sequence.h"
+#include "intern/depsgraph_type.h"
+
+struct Scene;
+
+namespace DEG {
+
+struct Depsgraph;
+
+/* Backup of sequencer strips runtime data. */
+class SequencerBackup {
+ public:
+ SequencerBackup(const Depsgraph *depsgraph);
+
+ void init_from_scene(Scene *scene);
+ void restore_to_scene(Scene *scene);
+
+ const Depsgraph *depsgraph;
+
+ typedef map<Sequence *, SequenceBackup> SequencesBackupMap;
+ SequencesBackupMap sequences_backup;
+};
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.cc
new file mode 100644
index 00000000000..0c54032e32c
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.cc
@@ -0,0 +1,64 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#include "intern/eval/deg_eval_runtime_backup_sound.h"
+
+#include "BLI_utildefines.h"
+
+#include "DNA_sound_types.h"
+
+namespace DEG {
+
+SoundBackup::SoundBackup(const Depsgraph * /*depsgraph*/)
+{
+ reset();
+}
+
+void SoundBackup::reset()
+{
+ cache = NULL;
+ waveform = NULL;
+ playback_handle = NULL;
+}
+
+void SoundBackup::init_from_sound(bSound *sound)
+{
+ cache = sound->cache;
+ waveform = sound->waveform;
+ playback_handle = sound->playback_handle;
+
+ sound->cache = NULL;
+ sound->waveform = NULL;
+ sound->playback_handle = NULL;
+}
+
+void SoundBackup::restore_to_sound(bSound *sound)
+{
+ sound->cache = cache;
+ sound->waveform = waveform;
+ sound->playback_handle = playback_handle;
+
+ reset();
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.h
new file mode 100644
index 00000000000..87783146701
--- /dev/null
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.h
@@ -0,0 +1,47 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2019 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+struct bSound;
+
+namespace DEG {
+
+struct Depsgraph;
+
+/* Backup of sound datablocks runtime data. */
+class SoundBackup {
+ public:
+ SoundBackup(const Depsgraph *depsgraph);
+
+ void reset();
+
+ void init_from_sound(bSound *sound);
+ void restore_to_sound(bSound *sound);
+
+ void *cache;
+ void *waveform;
+ void *playback_handle;
+};
+
+} // namespace DEG