Geometry Nodes: simplify handling of invalid group interface sockets

Previously, the code tried to keep node groups working even if some of
their input/output sockets had undefined type. This caused some
complexity with no benefit because not all places outside of this file
would handle the case correctly. Now node groups with undefined
interface sockets are disabled and have to be fixed manually before
they work again.

Undefined interface sockets are mostly caused by invalid Python
API usage and incomplete forward compatibility (e.g. when newer
versions introduce new socket types that the older version does
not know).
This commit is contained in:
Jacques Lucke 2022-12-16 18:30:47 +01:00
parent 6ced6c9545
commit 3aca0bc66a
4 changed files with 59 additions and 70 deletions

View File

@ -141,6 +141,8 @@ class bNodeTreeRuntime : NonCopyable, NonMovable {
bool has_undefined_nodes_or_sockets = false;
bNode *group_output_node = nullptr;
Vector<bNode *> root_frames;
Vector<bNodeSocket *> interface_inputs;
Vector<bNodeSocket *> interface_outputs;
};
/**
@ -426,6 +428,18 @@ inline blender::Span<const bNode *> bNodeTree::group_input_nodes() const
return this->nodes_by_type("NodeGroupInput");
}
inline blender::Span<const bNodeSocket *> bNodeTree::interface_inputs() const
{
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
return this->runtime->interface_inputs;
}
inline blender::Span<const bNodeSocket *> bNodeTree::interface_outputs() const
{
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
return this->runtime->interface_outputs;
}
inline blender::Span<const bNodeSocket *> bNodeTree::all_input_sockets() const
{
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));

View File

@ -42,6 +42,13 @@ static void double_checked_lock_with_task_isolation(std::mutex &mutex,
double_checked_lock(mutex, data_is_dirty, [&]() { threading::isolate_task(fn); });
}
static void update_interface_sockets(const bNodeTree &ntree)
{
bNodeTreeRuntime &tree_runtime = *ntree.runtime;
tree_runtime.interface_inputs = ntree.inputs;
tree_runtime.interface_outputs = ntree.outputs;
}
static void update_node_vector(const bNodeTree &ntree)
{
bNodeTreeRuntime &tree_runtime = *ntree.runtime;
@ -429,6 +436,7 @@ static void ensure_topology_cache(const bNodeTree &ntree)
bNodeTreeRuntime &tree_runtime = *ntree.runtime;
double_checked_lock_with_task_isolation(
tree_runtime.topology_cache_mutex, tree_runtime.topology_cache_is_dirty, [&]() {
update_interface_sockets(ntree);
update_node_vector(ntree);
update_link_vector(ntree);
update_socket_vectors_and_owner_node(ntree);

View File

@ -636,6 +636,9 @@ typedef struct bNodeTree {
const bNode *group_output_node() const;
/** Get all input nodes of the node group. */
blender::Span<const bNode *> group_input_nodes() const;
/** Inputs and outputs of the entire node group. */
blender::Span<const bNodeSocket *> interface_inputs() const;
blender::Span<const bNodeSocket *> interface_outputs() const;
#endif
} bNodeTree;

View File

@ -746,20 +746,9 @@ struct GeometryNodesLazyFunctionGraphBuilder {
/**
* All group input nodes are combined into one dummy node in the lazy-function graph.
* If some input has an invalid type, it is ignored in the new graph. In this case null and -1 is
* used in the vectors below.
*/
Vector<const CPPType *> group_input_types_;
Vector<int> group_input_indices_;
lf::DummyNode *group_input_lf_node_;
/**
* The output types or null if an output is invalid. Each group output node gets a separate
* corresponding dummy node in the new graph.
*/
Vector<const CPPType *> group_output_types_;
Vector<int> group_output_indices_;
public:
GeometryNodesLazyFunctionGraphBuilder(const bNodeTree &btree,
GeometryNodesLazyFunctionGraphInfo &lf_graph_info)
@ -776,8 +765,6 @@ struct GeometryNodesLazyFunctionGraphBuilder {
conversions_ = &bke::get_implicit_type_conversions();
this->prepare_node_multi_functions();
this->prepare_group_inputs();
this->prepare_group_outputs();
this->build_group_input_node();
this->handle_nodes();
this->handle_links();
@ -793,50 +780,21 @@ struct GeometryNodesLazyFunctionGraphBuilder {
lf_graph_info_->node_multi_functions = std::make_unique<NodeMultiFunctions>(btree_);
}
void prepare_group_inputs()
{
LISTBASE_FOREACH (const bNodeSocket *, interface_bsocket, &btree_.inputs) {
const CPPType *type = get_socket_cpp_type(*interface_bsocket->typeinfo);
if (type != nullptr) {
const int index = group_input_types_.append_and_get_index(type);
group_input_indices_.append(index);
}
else {
group_input_indices_.append(-1);
}
}
}
void prepare_group_outputs()
{
LISTBASE_FOREACH (const bNodeSocket *, interface_bsocket, &btree_.outputs) {
const CPPType *type = get_socket_cpp_type(*interface_bsocket->typeinfo);
if (type != nullptr) {
const int index = group_output_types_.append_and_get_index(type);
group_output_indices_.append(index);
}
else {
group_output_indices_.append(-1);
}
}
}
void build_group_input_node()
{
Vector<const CPPType *, 16> input_cpp_types;
const Span<const bNodeSocket *> interface_inputs = btree_.interface_inputs();
for (const bNodeSocket *interface_input : interface_inputs) {
input_cpp_types.append(interface_input->typeinfo->geometry_nodes_cpp_type);
}
/* Create a dummy node for the group inputs. */
auto debug_info = std::make_unique<GroupInputDebugInfo>();
group_input_lf_node_ = &lf_graph_->add_dummy({}, group_input_types_, debug_info.get());
group_input_lf_node_ = &lf_graph_->add_dummy({}, input_cpp_types, debug_info.get());
const bNodeSocket *interface_bsocket = static_cast<bNodeSocket *>(btree_.inputs.first);
for (const int group_input_index : group_input_indices_) {
BLI_SCOPED_DEFER([&]() { interface_bsocket = interface_bsocket->next; });
if (group_input_index == -1) {
mapping_->group_input_sockets.append(nullptr);
}
else {
mapping_->group_input_sockets.append(&group_input_lf_node_->output(group_input_index));
debug_info->socket_names.append(interface_bsocket->name);
}
for (const int i : interface_inputs.index_range()) {
mapping_->group_input_sockets.append(&group_input_lf_node_->output(i));
debug_info->socket_names.append(interface_inputs[i]->name);
}
lf_graph_info_->dummy_debug_infos_.append(std::move(debug_info));
}
@ -946,13 +904,9 @@ struct GeometryNodesLazyFunctionGraphBuilder {
void handle_group_input_node(const bNode &bnode)
{
for (const int btree_index : group_input_indices_.index_range()) {
const int lf_index = group_input_indices_[btree_index];
if (lf_index == -1) {
continue;
}
const bNodeSocket &bsocket = bnode.output_socket(btree_index);
lf::OutputSocket &lf_socket = group_input_lf_node_->output(lf_index);
for (const int i : btree_.interface_inputs().index_range()) {
const bNodeSocket &bsocket = bnode.output_socket(i);
lf::OutputSocket &lf_socket = group_input_lf_node_->output(i);
output_socket_map_.add_new(&bsocket, &lf_socket);
mapping_->dummy_socket_map.add_new(&bsocket, &lf_socket);
mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
@ -961,23 +915,23 @@ struct GeometryNodesLazyFunctionGraphBuilder {
void handle_group_output_node(const bNode &bnode)
{
Vector<const CPPType *, 16> output_cpp_types;
const Span<const bNodeSocket *> interface_outputs = btree_.interface_outputs();
for (const bNodeSocket *interface_input : interface_outputs) {
output_cpp_types.append(interface_input->typeinfo->geometry_nodes_cpp_type);
}
auto debug_info = std::make_unique<GroupOutputDebugInfo>();
lf::DummyNode &group_output_lf_node = lf_graph_->add_dummy(
group_output_types_, {}, debug_info.get());
output_cpp_types, {}, debug_info.get());
const bNodeSocket *interface_bsocket = static_cast<bNodeSocket *>(btree_.outputs.first);
for (const int btree_index : group_output_indices_.index_range()) {
BLI_SCOPED_DEFER([&]() { interface_bsocket = interface_bsocket->next; });
const int lf_index = group_output_indices_[btree_index];
if (lf_index == -1) {
continue;
}
const bNodeSocket &bsocket = bnode.input_socket(btree_index);
lf::InputSocket &lf_socket = group_output_lf_node.input(lf_index);
for (const int i : interface_outputs.index_range()) {
const bNodeSocket &bsocket = bnode.input_socket(i);
lf::InputSocket &lf_socket = group_output_lf_node.input(i);
input_socket_map_.add(&bsocket, &lf_socket);
mapping_->dummy_socket_map.add(&bsocket, &lf_socket);
mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
debug_info->socket_names.append(interface_bsocket->name);
debug_info->socket_names.append(interface_outputs[i]->name);
}
lf_graph_info_->dummy_debug_infos_.append(std::move(debug_info));
@ -1310,6 +1264,16 @@ const GeometryNodesLazyFunctionGraphInfo *ensure_geometry_nodes_lazy_function_gr
return nullptr;
}
}
for (const bNodeSocket *interface_bsocket : btree.interface_inputs()) {
if (interface_bsocket->typeinfo->geometry_nodes_cpp_type == nullptr) {
return nullptr;
}
}
for (const bNodeSocket *interface_bsocket : btree.interface_outputs()) {
if (interface_bsocket->typeinfo->geometry_nodes_cpp_type == nullptr) {
return nullptr;
}
}
std::unique_ptr<GeometryNodesLazyFunctionGraphInfo> &lf_graph_info_ptr =
btree.runtime->geometry_nodes_lazy_function_graph_info;