From b4e1e0946bf124f95e1d9fa1a6ffa1cbc143c7d6 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 2 May 2019 11:14:10 +0200 Subject: Depsgraph: Preserve sound and audio pointers through copy-on-write This allows to have scene and speaker copy-on-write executed without interrupting the playing sound. --- .../intern/eval/deg_eval_copy_on_write.cc | 219 ++++++++++++++++++++- 1 file changed, 218 insertions(+), 1 deletion(-) 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 b73c525ca13..6d5714d5606 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 @@ -60,6 +60,7 @@ extern "C" { #include "DNA_modifier_types.h" #include "DNA_scene_types.h" #include "DNA_sequence_types.h" +#include "DNA_sound_types.h" #include "DNA_object_types.h" #include "DNA_particle_types.h" @@ -85,6 +86,8 @@ extern "C" { #include "BKE_library_query.h" #include "BKE_modifier.h" #include "BKE_object.h" +#include "BKE_sequencer.h" +#include "BKE_sound.h" } #include "intern/depsgraph.h" @@ -859,6 +862,205 @@ ID *deg_expand_copy_on_write_datablock(const Depsgraph *depsgraph, 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 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 restorted: we just copy them over to a new scene. */ + void *sound_scene; + void *playback_handle; + void *sound_scrub_handle; + void *speaker_handles; + + SequencerBackup sequencer_backup; +}; + +SceneBackup::SceneBackup() +{ + reset(); +} + +void SceneBackup::reset() +{ + sound_scene = NULL; + playback_handle = NULL; + sound_scrub_handle = NULL; + speaker_handles = NULL; +} + +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; + + /* 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; + + 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. @@ -899,7 +1101,8 @@ typedef map ModifierRuntimeDataBackup; /* Storage for backed up pose channel runtime data. */ typedef map PoseChannelRuntimeDataBackup; -struct ObjectRuntimeBackup { +class ObjectRuntimeBackup { + public: ObjectRuntimeBackup() : base_flag(0), base_local_view_bits(0) { /* TODO(sergey): Use something like BKE_object_runtime_reset(). */ @@ -1077,6 +1280,8 @@ class RuntimeBackup { /* 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; @@ -1092,6 +1297,12 @@ void RuntimeBackup::init_from_id(ID *id) case ID_OB: object_backup.init_from_object(reinterpret_cast(id)); break; + case ID_SCE: + scene_backup.init_from_scene(reinterpret_cast(id)); + break; + case ID_SO: + sound_backup.init_from_sound(reinterpret_cast(id)); + break; default: break; } @@ -1111,6 +1322,12 @@ void RuntimeBackup::restore_to_id(ID *id) case ID_OB: object_backup.restore_to_object(reinterpret_cast(id)); break; + case ID_SCE: + scene_backup.restore_to_scene(reinterpret_cast(id)); + break; + case ID_SO: + sound_backup.restore_to_sound(reinterpret_cast(id)); + break; default: break; } -- cgit v1.2.3