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:
		@@ -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;
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user