1
1

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.
This commit is contained in:
2019-05-02 11:14:10 +02:00
parent 4eedf784b0
commit b4e1e0946b

View File

@@ -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<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 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<ModifierDataBackupID, void *> ModifierRuntimeDataBackup;
/* Storage for backed up pose channel runtime data. */
typedef map<bPoseChannel *, bPoseChannel_Runtime> 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<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;
default:
break;
}
@@ -1111,6 +1322,12 @@ void RuntimeBackup::restore_to_id(ID *id)
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;
default:
break;
}