From 62c807fa71d910a248c245a0e9b8941b10923993 Mon Sep 17 00:00:00 2001 From: Marc Gilleron Date: Wed, 22 Sep 2021 20:28:17 +0100 Subject: [PATCH] Fix graph not recompiling after changing a subresource --- generators/graph/program_graph.h | 11 +++- generators/graph/voxel_generator_graph.cpp | 62 ++++++++++++++++++++-- generators/graph/voxel_generator_graph.h | 6 +-- generators/graph/voxel_graph_runtime.cpp | 2 +- 4 files changed, 71 insertions(+), 10 deletions(-) diff --git a/generators/graph/program_graph.h b/generators/graph/program_graph.h index 3297e455..9bd67398 100644 --- a/generators/graph/program_graph.h +++ b/generators/graph/program_graph.h @@ -68,7 +68,7 @@ public: void find_terminal_nodes(std::vector &node_ids) const; template - inline void for_each_node(F f) const { + inline void for_each_node_const(F f) const { for (auto it = _nodes.begin(); it != _nodes.end(); ++it) { const Node *node = it->second; ERR_CONTINUE(node == nullptr); @@ -76,6 +76,15 @@ public: } } + template + inline void for_each_node(F f) { + for (auto it = _nodes.begin(); it != _nodes.end(); ++it) { + Node *node = it->second; + ERR_CONTINUE(node == nullptr); + f(*node); + } + } + void copy_from(const ProgramGraph &other, bool copy_subresources); void get_connections(std::vector &connections) const; //void get_connections_from_and_to(std::vector &connections, uint32_t node_id) const; diff --git a/generators/graph/voxel_generator_graph.cpp b/generators/graph/voxel_generator_graph.cpp index a073532b..48e292c3 100644 --- a/generators/graph/voxel_generator_graph.cpp +++ b/generators/graph/voxel_generator_graph.cpp @@ -1,4 +1,5 @@ #include "voxel_generator_graph.h" +#include "../../util/macros.h" #include "../../util/profiling.h" #include "../../util/profiling_clock.h" #include "voxel_graph_node_db.h" @@ -17,6 +18,14 @@ VoxelGeneratorGraph::~VoxelGeneratorGraph() { } void VoxelGeneratorGraph::clear() { + _graph.for_each_node([this](ProgramGraph::Node &node) { + for (size_t i = 0; i < node.params.size(); ++i) { + Ref resource = node.params[i]; + if (resource.is_valid()) { + unregister_subresource(**resource); + } + } + }); _graph.clear(); { RWLockWrite wlock(_runtime_lock); @@ -54,7 +63,14 @@ uint32_t VoxelGeneratorGraph::create_node(NodeTypeID type_id, Vector2 position, } void VoxelGeneratorGraph::remove_node(uint32_t node_id) { - ERR_FAIL_COND(_graph.try_get_node(node_id) == nullptr); + ProgramGraph::Node *node = _graph.try_get_node(node_id); + ERR_FAIL_COND(node == nullptr); + for (size_t i = 0; i < node->params.size(); ++i) { + Ref resource = node->params[i]; + if (resource.is_valid()) { + unregister_subresource(**resource); + } + } _graph.remove_node(node_id); emit_changed(); } @@ -141,7 +157,18 @@ void VoxelGeneratorGraph::set_node_param(uint32_t node_id, uint32_t param_index, ERR_FAIL_INDEX(param_index, node->params.size()); if (node->params[param_index] != value) { + Ref prev_resource = node->params[param_index]; + if (prev_resource.is_valid()) { + unregister_subresource(**prev_resource); + } + node->params[param_index] = value; + + Ref resource = value; + if (resource.is_valid()) { + register_subresource(**resource); + } + emit_changed(); } } @@ -569,6 +596,8 @@ VoxelGenerator::Result VoxelGeneratorGraph::generate_block(VoxelBlockRequest &in } VoxelGraphRuntime::CompilationResult VoxelGeneratorGraph::compile() { + const int64_t time_before = OS::get_singleton()->get_ticks_usec(); + std::shared_ptr r = std::make_shared(); VoxelGraphRuntime &runtime = r->runtime; @@ -694,6 +723,9 @@ VoxelGraphRuntime::CompilationResult VoxelGeneratorGraph::compile() { RWLockWrite wlock(_runtime_lock); _runtime = r; + const int64_t time_spent = OS::get_singleton()->get_ticks_usec() - time_before; + PRINT_VERBOSE(String("Voxel graph compiled in {0} us").format(varray(time_spent))); + return result; } @@ -1199,15 +1231,35 @@ static bool load_graph_from_variant_data(ProgramGraph &graph, Dictionary data) { } void VoxelGeneratorGraph::load_graph_from_variant_data(Dictionary data) { + clear(); + if (::load_graph_from_variant_data(_graph, data)) { + _graph.for_each_node([this](ProgramGraph::Node &node) { + for (size_t i = 0; i < node.params.size(); ++i) { + Ref resource = node.params[i]; + if (resource.is_valid()) { + register_subresource(**resource); + } + } + }); + // It's possible to auto-compile on load because `graph_data` is the only property set by the loader, // which is enough to have all information we need compile(); + } else { _graph.clear(); } } +void VoxelGeneratorGraph::register_subresource(Resource &resource) { + resource.connect(CoreStringNames::get_singleton()->changed, this, "_on_subresource_changed"); +} + +void VoxelGeneratorGraph::unregister_subresource(Resource &resource) { + resource.disconnect(CoreStringNames::get_singleton()->changed, this, "_on_subresource_changed"); +} + // Debug land float VoxelGeneratorGraph::debug_measure_microseconds_per_voxel(bool singular) { @@ -1400,9 +1452,9 @@ Dictionary VoxelGeneratorGraph::_b_compile() { return d; } -// void VoxelGeneratorGraph::_on_subresource_changed() { -// emit_changed(); -// } +void VoxelGeneratorGraph::_on_subresource_changed() { + emit_changed(); +} void VoxelGeneratorGraph::_bind_methods() { ClassDB::bind_method(D_METHOD("clear"), &VoxelGeneratorGraph::clear); @@ -1476,7 +1528,7 @@ void VoxelGeneratorGraph::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_graph_data", "data"), &VoxelGeneratorGraph::load_graph_from_variant_data); ClassDB::bind_method(D_METHOD("_get_graph_data"), &VoxelGeneratorGraph::get_graph_as_variant_data); - // ClassDB::bind_method(D_METHOD("_on_subresource_changed"), &VoxelGeneratorGraph::_on_subresource_changed); + ClassDB::bind_method(D_METHOD("_on_subresource_changed"), &VoxelGeneratorGraph::_on_subresource_changed); ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "graph_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), diff --git a/generators/graph/voxel_generator_graph.h b/generators/graph/voxel_generator_graph.h index aa89e679..fd92f927 100644 --- a/generators/graph/voxel_generator_graph.h +++ b/generators/graph/voxel_generator_graph.h @@ -159,6 +159,9 @@ public: private: Dictionary get_graph_as_variant_data() const; void load_graph_from_variant_data(Dictionary data); + void register_subresource(Resource &resource); + void unregister_subresource(Resource &resource); + void _on_subresource_changed(); int _b_get_node_type_count() const; Dictionary _b_get_node_type_info(int type_id) const; @@ -171,9 +174,6 @@ private: Vector2 _b_debug_analyze_range(Vector3 min_pos, Vector3 max_pos) const; Dictionary _b_compile(); - void _on_subresource_changed(); - void connect_to_subresource_changes(); - struct WeightOutput { unsigned int layer_index; unsigned int output_buffer_index; diff --git a/generators/graph/voxel_graph_runtime.cpp b/generators/graph/voxel_graph_runtime.cpp index e84a5068..fb3f6524 100644 --- a/generators/graph/voxel_graph_runtime.cpp +++ b/generators/graph/voxel_graph_runtime.cpp @@ -83,7 +83,7 @@ VoxelGraphRuntime::CompilationResult VoxelGraphRuntime::_compile(const ProgramGr std::unordered_map node_id_to_dependency_graph; // Not using the generic `get_terminal_nodes` function because our terminal nodes do have outputs - graph.for_each_node([&terminal_nodes](const ProgramGraph::Node &node) { + graph.for_each_node_const([&terminal_nodes](const ProgramGraph::Node &node) { const VoxelGraphNodeDB::NodeType &type = VoxelGraphNodeDB::get_singleton()->get_type(node.type_id); if (type.category == VoxelGraphNodeDB::CATEGORY_OUTPUT) { terminal_nodes.push_back(node.id);