Sound: Port to a copy-on-write concept

This change makes it so sound handles are created for evaluated scene,
sequencer and speakers. This allows to have properly evaluated animation
on them.

For the viewport playback sound uses regular dependency graph.

For the final render sound uses dependency graph created for render pipeline,
which now also contains sequencer and sound datablocks.

All the direct sound update calls are replaced with corresponding dependency
graph recalc tag.
This commit is contained in:
2019-06-04 16:52:48 +02:00
parent 863b7b3668
commit bbaa1bffe9
44 changed files with 887 additions and 279 deletions

View File

@@ -85,6 +85,16 @@ void DEG_get_customdata_mask_for_object(const struct Depsgraph *graph,
* one. Assert will happen if it's not. */
struct Scene *DEG_get_evaluated_scene(const struct Depsgraph *graph);
/* Similar to DEG_get_evaluated_scene(), but allows to access non-fully evaluated pointer without
* causing asserts or crashes. Works the following way:
* - If the scene was never evaluated NULL returned.
* - Otherwise the last known state of the scene is returned.
*
* Use in exceptional case if it's absolutely must to.
*
* Allows to pass depsgraph == NULL, wil lreturn NULL in that case. */
struct Scene *DEG_get_evaluated_scene_if_exists(const struct Depsgraph *graph);
/* Get view layer at its evaluated state.
* This is a shortcut for accessing active view layer from evaluated scene. */
struct ViewLayer *DEG_get_evaluated_view_layer(const struct Depsgraph *graph);

View File

@@ -58,6 +58,7 @@ extern "C" {
#include "DNA_lightprobe_types.h"
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
#include "DNA_sound_types.h"
#include "DNA_speaker_types.h"
#include "DNA_texture_types.h"
@@ -89,6 +90,8 @@ extern "C" {
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_rigidbody.h"
#include "BKE_scene.h"
#include "BKE_sequencer.h"
#include "BKE_shader_fx.h"
#include "BKE_sound.h"
#include "BKE_tracking.h"
@@ -1564,12 +1567,42 @@ void DepsgraphNodeBuilder::build_sound(bSound *sound)
if (built_map_.checkIsBuiltAndTag(sound)) {
return;
}
/* Placeholder so we can add relations and tag ID node for update. */
add_operation_node(&sound->id, NodeType::AUDIO, OperationCode::SOUND_EVAL);
add_id_node(&sound->id);
bSound *sound_cow = get_cow_datablock(sound);
add_operation_node(&sound->id,
NodeType::AUDIO,
OperationCode::SOUND_EVAL,
function_bind(BKE_sound_evaluate, _1, bmain_, sound_cow));
build_animdata(&sound->id);
build_parameters(&sound->id);
}
void DepsgraphNodeBuilder::build_scene_sequencer(Scene *scene)
{
if (scene->ed == NULL) {
return;
}
Scene *scene_cow = get_cow_datablock(scene_);
add_operation_node(&scene->id,
NodeType::SEQUENCER,
OperationCode::SEQUENCES_EVAL,
function_bind(BKE_scene_eval_sequencer_sequences, _1, scene_cow));
/* Make sure data for sequences is in the graph. */
Sequence *seq;
SEQ_BEGIN (scene->ed, seq) {
if (seq->sound != NULL) {
build_sound(seq->sound);
}
/* TODO(sergey): Movie clip, scene, camera, mask. */
}
SEQ_END;
}
void DepsgraphNodeBuilder::build_scene_audio(Scene *scene)
{
add_operation_node(&scene->id, NodeType::AUDIO, OperationCode::SOUND_EVAL);
}
/* **** ID traversal callbacks functions **** */
void DepsgraphNodeBuilder::modifier_walk(void *user_data,

View File

@@ -212,6 +212,8 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
void build_lightprobe(LightProbe *probe);
void build_speaker(Speaker *speaker);
void build_sound(bSound *sound);
void build_scene_sequencer(Scene *scene);
void build_scene_audio(Scene *scene);
/* Per-ID information about what was already in the dependency graph.
* Allows to re-use certain values, to speed up following evaluation. */

View File

@@ -31,13 +31,19 @@ void DepsgraphNodeBuilder::build_scene_render(Scene *scene)
{
scene_ = scene;
const bool build_compositor = (scene->r.scemode & R_DOCOMP);
const bool build_sequencer = (scene->r.scemode & R_DOSEQ);
IDNode *id_node = add_id_node(&scene->id);
id_node->linked_state = DEG_ID_LINKED_DIRECTLY;
add_time_source();
build_animdata(&scene->id);
build_scene_parameters(scene);
build_scene_audio(scene);
if (build_compositor) {
build_scene_compositor(scene);
}
if (build_sequencer) {
build_scene_sequencer(scene);
}
}
void DepsgraphNodeBuilder::build_scene_parameters(Scene *scene)

View File

@@ -146,6 +146,11 @@ void DepsgraphNodeBuilder::build_view_layer(Scene *scene,
build_collection(NULL, fls->group);
}
}
/* Sequencer. */
if (linked_state == DEG_ID_LINKED_DIRECTLY) {
build_scene_audio(scene);
build_scene_sequencer(scene);
}
/* Collections. */
add_operation_node(
&scene->id,

View File

@@ -58,6 +58,7 @@ extern "C" {
#include "DNA_object_types.h"
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
#include "DNA_sound_types.h"
#include "DNA_speaker_types.h"
#include "DNA_texture_types.h"
@@ -84,6 +85,7 @@ extern "C" {
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_rigidbody.h"
#include "BKE_sequencer.h"
#include "BKE_shader_fx.h"
#include "BKE_shrinkwrap.h"
#include "BKE_sound.h"
@@ -2324,6 +2326,35 @@ void DepsgraphRelationBuilder::build_sound(bSound *sound)
build_parameters(&sound->id);
}
void DepsgraphRelationBuilder::build_scene_sequencer(Scene *scene)
{
if (scene->ed == NULL) {
return;
}
/* Make sure dependencies from sequences data goes to the sequencer evaluation. */
ComponentKey sequencer_key(&scene->id, NodeType::SEQUENCER);
Sequence *seq;
bool has_audio_strips = false;
SEQ_BEGIN (scene->ed, seq) {
if (seq->sound != NULL) {
build_sound(seq->sound);
ComponentKey sound_key(&seq->sound->id, NodeType::AUDIO);
add_relation(sound_key, sequencer_key, "Sound -> Sequencer");
has_audio_strips = true;
}
/* TODO(sergey): Movie clip, scene, camera, mask. */
}
SEQ_END;
if (has_audio_strips) {
ComponentKey scene_audio_key(&scene->id, NodeType::AUDIO);
add_relation(sequencer_key, scene_audio_key, "Sequencer -> Audio");
}
}
void DepsgraphRelationBuilder::build_scene_audio(Scene * /*scene*/)
{
}
void DepsgraphRelationBuilder::build_copy_on_write_relations()
{
for (IDNode *id_node : graph_->id_nodes) {
@@ -2387,6 +2418,10 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations(IDNode *id_node)
(id_type == ID_CF && comp_node->type == NodeType::CACHE)) {
rel_flag &= ~RELATION_FLAG_NO_FLUSH;
}
/* TODO(sergey): Needs better solution for this. */
if (id_type == ID_SO) {
rel_flag &= ~RELATION_FLAG_NO_FLUSH;
}
/* Notes on exceptions:
* - Parameters component is where drivers are living. Changing any
* of the (custom) properties in the original datablock (even the

View File

@@ -41,6 +41,7 @@
#include "intern/builder/deg_builder_rna.h"
#include "intern/depsgraph.h"
#include "intern/node/deg_node.h"
#include "intern/node/deg_node_id.h"
#include "intern/node/deg_node_component.h"
#include "intern/node/deg_node_operation.h"
@@ -200,7 +201,9 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder {
void build_scene_compositor(Scene *scene);
void build_layer_collections(ListBase *lb);
void build_view_layer(Scene *scene, ViewLayer *view_layer);
void build_view_layer(Scene *scene,
ViewLayer *view_layer,
eDepsNode_LinkedState_Type linked_state);
void build_collection(LayerCollection *from_layer_collection,
Object *object,
Collection *collection);
@@ -270,6 +273,8 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder {
void build_lightprobe(LightProbe *probe);
void build_speaker(Speaker *speaker);
void build_sound(bSound *sound);
void build_scene_sequencer(Scene *scene);
void build_scene_audio(Scene *scene);
void build_nested_datablock(ID *owner, ID *id);
void build_nested_nodetree(ID *owner, bNodeTree *ntree);

View File

@@ -31,10 +31,16 @@ void DepsgraphRelationBuilder::build_scene_render(Scene *scene)
{
scene_ = scene;
const bool build_compositor = (scene->r.scemode & R_DOCOMP);
const bool build_sequencer = (scene->r.scemode & R_DOSEQ);
build_scene_parameters(scene);
build_animdata(&scene->id);
build_scene_audio(scene);
if (build_compositor) {
build_scene_compositor(scene);
}
if (build_sequencer) {
build_scene_sequencer(scene);
}
}
void DepsgraphRelationBuilder::build_scene_parameters(Scene *scene)

View File

@@ -75,7 +75,9 @@ void DepsgraphRelationBuilder::build_layer_collections(ListBase *lb)
}
}
void DepsgraphRelationBuilder::build_view_layer(Scene *scene, ViewLayer *view_layer)
void DepsgraphRelationBuilder::build_view_layer(Scene *scene,
ViewLayer *view_layer,
eDepsNode_LinkedState_Type linked_state)
{
/* Setup currently building context. */
scene_ = scene;
@@ -132,10 +134,15 @@ void DepsgraphRelationBuilder::build_view_layer(Scene *scene, ViewLayer *view_la
&scene->id, NodeType::LAYER_COLLECTIONS, OperationCode::VIEW_LAYER_EVAL);
OperationKey scene_eval_key(&scene->id, NodeType::PARAMETERS, OperationCode::SCENE_EVAL);
add_relation(scene_view_layer_key, scene_eval_key, "View Layer -> Scene Eval");
/* Sequencer. */
if (linked_state == DEG_ID_LINKED_DIRECTLY) {
build_scene_audio(scene);
build_scene_sequencer(scene);
}
/* Build all set scenes. */
if (scene->set != NULL) {
ViewLayer *set_view_layer = BKE_view_layer_default_render(scene->set);
build_view_layer(scene->set, set_view_layer);
build_view_layer(scene->set, set_view_layer, DEG_ID_LINKED_VIA_SET);
}
}

View File

@@ -329,10 +329,8 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr,
return node_identifier;
}
else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) {
const Sequence *seq = static_cast<Sequence *>(ptr->data);
/* Sequencer strip */
node_identifier.type = NodeType::SEQUENCER;
node_identifier.component_name = seq->name;
return node_identifier;
}
else if (RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) {

View File

@@ -272,7 +272,7 @@ void DEG_graph_build_from_view_layer(Depsgraph *graph,
/* Hook up relationships between operations - to determine evaluation order. */
DEG::DepsgraphRelationBuilder relation_builder(bmain, deg_graph, &builder_cache);
relation_builder.begin_build();
relation_builder.build_view_layer(scene, view_layer);
relation_builder.build_view_layer(scene, view_layer, DEG::DEG_ID_LINKED_DIRECTLY);
relation_builder.build_copy_on_write_relations();
/* Finalize building. */
graph_build_finalize_common(deg_graph, bmain);

View File

@@ -160,6 +160,19 @@ Scene *DEG_get_evaluated_scene(const Depsgraph *graph)
return scene_cow;
}
Scene *DEG_get_evaluated_scene_if_exists(const Depsgraph *graph)
{
if (graph == NULL) {
return NULL;
}
const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph);
Scene *scene_cow = deg_graph->scene_cow;
if (scene_cow == NULL || !DEG::deg_copy_on_write_is_expanded(&scene_cow->id)) {
return NULL;
}
return scene_cow;
}
ViewLayer *DEG_get_evaluated_view_layer(const Depsgraph *graph)
{
const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph);

View File

@@ -215,6 +215,16 @@ void depsgraph_tag_to_component_opcode(const ID *id,
/* There is no such node in depsgraph, this tag is to be handled
* separately. */
break;
case ID_RECALC_SEQUENCER_STRIPS:
*component_type = NodeType::SEQUENCER;
break;
case ID_RECALC_AUDIO_SEEK:
case ID_RECALC_AUDIO_FPS:
case ID_RECALC_AUDIO_VOLUME:
case ID_RECALC_AUDIO_MUTE:
case ID_RECALC_AUDIO_LISTENER:
*component_type = NodeType::AUDIO;
break;
case ID_RECALC_ALL:
case ID_RECALC_PSYS_ALL:
BLI_assert(!"Should not happen");
@@ -633,6 +643,18 @@ const char *DEG_update_tag_as_string(IDRecalcFlag flag)
return "POINT_CACHE";
case ID_RECALC_EDITORS:
return "EDITORS";
case ID_RECALC_SEQUENCER_STRIPS:
return "SEQUENCER_STRIPS";
case ID_RECALC_AUDIO_SEEK:
return "AUDIO_SEEK";
case ID_RECALC_AUDIO_FPS:
return "AUDIO_FPS";
case ID_RECALC_AUDIO_VOLUME:
return "AUDIO_VOLUME";
case ID_RECALC_AUDIO_MUTE:
return "AUDIO_MUTE";
case ID_RECALC_AUDIO_LISTENER:
return "AUDIO_LISTENER";
case ID_RECALC_ALL:
return "ALL";
}

View File

@@ -59,6 +59,8 @@ extern "C" {
#include "DNA_mesh_types.h"
#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"
@@ -84,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"
@@ -467,6 +471,25 @@ void scene_setup_view_layers_after_remap(const Depsgraph *depsgraph,
* Still not an excuse to have those. */
}
void update_sequence_orig_pointers(const ListBase *sequences_orig, ListBase *sequences_cow)
{
Sequence *sequence_orig = reinterpret_cast<Sequence *>(sequences_orig->first);
Sequence *sequence_cow = reinterpret_cast<Sequence *>(sequences_cow->first);
while (sequence_orig != NULL) {
update_sequence_orig_pointers(&sequence_orig->seqbase, &sequence_cow->seqbase);
sequence_cow->orig_sequence = sequence_orig;
sequence_cow = sequence_cow->next;
sequence_orig = sequence_orig->next;
}
}
void update_scene_orig_pointers(const Scene *scene_orig, Scene *scene_cow)
{
if (scene_orig->ed != NULL) {
update_sequence_orig_pointers(&scene_orig->ed->seqbase, &scene_cow->ed->seqbase);
}
}
/* Check whether given ID is expanded or still a shallow copy. */
BLI_INLINE bool check_datablock_expanded(const ID *id_cow)
{
@@ -751,6 +774,7 @@ void update_id_after_copy(const Depsgraph *depsgraph,
scene_cow->toolsettings = scene_orig->toolsettings;
scene_cow->eevee.light_cache = scene_orig->eevee.light_cache;
scene_setup_view_layers_after_remap(depsgraph, id_node, reinterpret_cast<Scene *>(id_cow));
update_scene_orig_pointers(scene_orig, scene_cow);
break;
}
default:
@@ -881,6 +905,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.
@@ -921,7 +1144,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(). */
@@ -1099,6 +1323,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;
@@ -1114,6 +1340,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;
}
@@ -1133,6 +1365,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;
}
@@ -1321,9 +1559,7 @@ bool deg_copy_on_write_is_expanded(const ID *id_cow)
bool deg_copy_on_write_is_needed(const ID *id_orig)
{
const ID_Type id_type = GS(id_orig->name);
/* TODO(sergey): Make Sound copyable. It is here only because the code for dependency graph is
* being work in progress. */
return !ELEM(id_type, ID_IM, ID_SO);
return !ELEM(id_type, ID_IM);
}
} // namespace DEG

View File

@@ -185,6 +185,9 @@ const char *operationCodeAsString(OperationCode opcode)
/* Generic datablock. */
case OperationCode::GENERIC_DATABLOCK_UPDATE:
return "GENERIC_DATABLOCK_UPDATE";
/* Sequencer. */
case OperationCode::SEQUENCES_EVAL:
return "SEQUENCES_EVAL";
/* instancing/duplication. */
case OperationCode::DUPLI:
return "DUPLI";

View File

@@ -185,12 +185,16 @@ enum class OperationCode {
/* Images. -------------------------------------------------------------- */
IMAGE_ANIMATION,
/* Synchronization clips. ----------------------------------------------- */
/* Synchronization. ----------------------------------------------------- */
SYNCHRONIZE_TO_ORIGINAL,
/* Generic datablock ---------------------------------------------------- */
GENERIC_DATABLOCK_UPDATE,
/* Sequencer. ----------------------------------------------------------- */
SEQUENCES_EVAL,
/* Duplication/instancing system. --------------------------------------- */
DUPLI,
};