Geometry Nodes: make evaluation and logging system aware of zones #109029

Closed
Jacques Lucke wants to merge 93 commits from JacquesLucke/blender:zone-evaluation into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
20 changed files with 2013 additions and 1167 deletions

View File

@ -87,8 +87,12 @@ class SPREADSHEET_HT_header(bpy.types.Header):
layout.label(text="Invalid id")
elif ctx.type == 'MODIFIER':
layout.label(text=ctx.modifier_name, icon='MODIFIER')
elif ctx.type == 'NODE':
layout.label(text=ctx.node_name, icon='NODE')
elif ctx.type == 'GROUP_NODE':
layout.label(text=ctx.ui_name, icon='NODE')
elif ctx.type == 'SIMULATION_ZONE':
layout.label(text="Simulation Zone")
elif ctx.type == 'VIEWER_NODE':
layout.label(text=ctx.ui_name)
def draw_spreadsheet_viewer_path_icon(self, layout, space, icon='RIGHTARROW_THIN'):
layout.prop(space, "display_viewer_path_collapsed", icon_only=True, emboss=False, icon=icon)

View File

@ -59,4 +59,23 @@ class NodeGroupComputeContext : public ComputeContext {
void print_current_in_line(std::ostream &stream) const override;
};
class SimulationZoneComputeContext : public ComputeContext {
private:
static constexpr const char *s_static_type = "SIMULATION_ZONE";
int32_t output_node_id_;
public:
SimulationZoneComputeContext(const ComputeContext *parent, int output_node_id);
SimulationZoneComputeContext(const ComputeContext *parent, const bNode &node);
int32_t output_node_id() const
{
return output_node_id_;
}
private:
void print_current_in_line(std::ostream &stream) const override;
};
} // namespace blender::bke

View File

@ -14,6 +14,8 @@
namespace blender::bke::node_tree_zones {
class TreeZones;
struct TreeZone {
TreeZones *owner = nullptr;
/** Index of the zone in the array of all zones in a node tree. */
@ -53,8 +55,25 @@ class TreeZones {
* in a different zone than its output sockets.
*/
const TreeZone *get_zone_by_socket(const bNodeSocket &socket) const;
/**
* Get the deepest zone that the node is in. Note that the e.g. Simulation Input and Output nodes
* are considered to be inside of the zone they create.
*/
const TreeZone *get_zone_by_node(const int32_t node_id) const;
/**
* Get a sorted list of zones that the node is in. First comes the root zone and last the most
* nested zone. For nodes that are at the root level, the returned list is empty.
*/
Vector<const TreeZone *> get_zone_stack_for_node(const int32_t node_id) const;
};
const TreeZones *get_tree_zones(const bNodeTree &tree);
} // namespace blender::bke::node_tree_zones
inline const blender::bke::node_tree_zones::TreeZones *bNodeTree::zones() const
{
return blender::bke::node_tree_zones::get_tree_zones(*this);
}

View File

@ -50,7 +50,9 @@ void BKE_viewer_path_id_remap(ViewerPath *viewer_path, const struct IDRemapper *
ViewerPathElem *BKE_viewer_path_elem_new(ViewerPathElemType type);
IDViewerPathElem *BKE_viewer_path_elem_new_id(void);
ModifierViewerPathElem *BKE_viewer_path_elem_new_modifier(void);
NodeViewerPathElem *BKE_viewer_path_elem_new_node(void);
GroupNodeViewerPathElem *BKE_viewer_path_elem_new_group_node(void);
SimulationZoneViewerPathElem *BKE_viewer_path_elem_new_simulation_zone(void);
ViewerNodeViewerPathElem *BKE_viewer_path_elem_new_viewer_node(void);
ViewerPathElem *BKE_viewer_path_elem_copy(const ViewerPathElem *src);
bool BKE_viewer_path_elem_equal(const ViewerPathElem *a, const ViewerPathElem *b);
void BKE_viewer_path_elem_free(ViewerPathElem *elem);

View File

@ -62,4 +62,30 @@ void NodeGroupComputeContext::print_current_in_line(std::ostream &stream) const
stream << "Node ID: " << node_id_;
}
SimulationZoneComputeContext::SimulationZoneComputeContext(const ComputeContext *parent,
const int32_t output_node_id)
: ComputeContext(s_static_type, parent), output_node_id_(output_node_id)
{
/* Mix static type and node id into a single buffer so that only a single call to #mix_in is
* necessary. */
const int type_size = strlen(s_static_type);
const int buffer_size = type_size + 1 + sizeof(int32_t);
DynamicStackBuffer<64, 8> buffer_owner(buffer_size, 8);
char *buffer = static_cast<char *>(buffer_owner.buffer());
memcpy(buffer, s_static_type, type_size + 1);
memcpy(buffer + type_size + 1, &output_node_id_, sizeof(int32_t));
hash_.mix_in(buffer, buffer_size);
}
SimulationZoneComputeContext::SimulationZoneComputeContext(const ComputeContext *parent,
const bNode &node)
: SimulationZoneComputeContext(parent, node.identifier)
{
}
void SimulationZoneComputeContext::print_current_in_line(std::ostream &stream) const
{
stream << "Simulation Zone ID: " << output_node_id_;
}
} // namespace blender::bke

View File

@ -309,22 +309,44 @@ bool TreeZone::contains_zone_recursively(const TreeZone &other_zone) const
const TreeZone *TreeZones::get_zone_by_socket(const bNodeSocket &socket) const
{
const bNode &node = socket.owner_node();
const int zone_i = this->zone_by_node_id.lookup_default(node.identifier, -1);
const TreeZone *zone = this->get_zone_by_node(node.identifier);
if (zone == nullptr) {
return zone;
}
if (zone->input_node == &node) {
if (socket.is_input()) {
return zone->parent_zone;
}
}
if (zone->output_node == &node) {
if (socket.is_output()) {
return zone->parent_zone;
}
}
return zone;
}
const TreeZone *TreeZones::get_zone_by_node(const int32_t node_id) const
{
const int zone_i = this->zone_by_node_id.lookup_default(node_id, -1);
if (zone_i == -1) {
return nullptr;
}
const TreeZone &zone = *this->zones[zone_i];
if (zone.input_node == &node) {
if (socket.is_input()) {
return zone.parent_zone;
}
return this->zones[zone_i].get();
}
Vector<const TreeZone *> TreeZones::get_zone_stack_for_node(const int node_id) const
{
const TreeZone *zone = this->get_zone_by_node(node_id);
if (zone == nullptr) {
return {};
}
if (zone.output_node == &node) {
if (socket.is_output()) {
return zone.parent_zone;
}
Vector<const TreeZone *> zone_stack;
for (; zone; zone = zone->parent_zone) {
zone_stack.append(zone);
}
return &zone;
std::reverse(zone_stack.begin(), zone_stack.end());
return zone_stack;
}
} // namespace blender::bke::node_tree_zones

View File

@ -73,13 +73,23 @@ void BKE_viewer_path_blend_write(BlendWriter *writer, const ViewerPath *viewer_p
BLO_write_string(writer, typed_elem->modifier_name);
break;
}
case VIEWER_PATH_ELEM_TYPE_NODE: {
const auto *typed_elem = reinterpret_cast<NodeViewerPathElem *>(elem);
BLO_write_struct(writer, NodeViewerPathElem, typed_elem);
BLO_write_string(writer, typed_elem->node_name);
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: {
const auto *typed_elem = reinterpret_cast<GroupNodeViewerPathElem *>(elem);
BLO_write_struct(writer, GroupNodeViewerPathElem, typed_elem);
break;
}
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: {
const auto *typed_elem = reinterpret_cast<SimulationZoneViewerPathElem *>(elem);
BLO_write_struct(writer, SimulationZoneViewerPathElem, typed_elem);
break;
}
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: {
const auto *typed_elem = reinterpret_cast<ViewerNodeViewerPathElem *>(elem);
BLO_write_struct(writer, ViewerNodeViewerPathElem, typed_elem);
break;
}
}
BLO_write_string(writer, elem->ui_name);
}
}
@ -87,7 +97,11 @@ void BKE_viewer_path_blend_read_data(BlendDataReader *reader, ViewerPath *viewer
{
BLO_read_list(reader, &viewer_path->path);
LISTBASE_FOREACH (ViewerPathElem *, elem, &viewer_path->path) {
BLO_read_data_address(reader, &elem->ui_name);
switch (ViewerPathElemType(elem->type)) {
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE:
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE:
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE:
case VIEWER_PATH_ELEM_TYPE_ID: {
break;
}
@ -96,11 +110,6 @@ void BKE_viewer_path_blend_read_data(BlendDataReader *reader, ViewerPath *viewer
BLO_read_data_address(reader, &typed_elem->modifier_name);
break;
}
case VIEWER_PATH_ELEM_TYPE_NODE: {
auto *typed_elem = reinterpret_cast<NodeViewerPathElem *>(elem);
BLO_read_data_address(reader, &typed_elem->node_name);
break;
}
}
}
}
@ -115,7 +124,9 @@ void BKE_viewer_path_blend_read_lib(BlendLibReader *reader, ID *self_id, ViewerP
break;
}
case VIEWER_PATH_ELEM_TYPE_MODIFIER:
case VIEWER_PATH_ELEM_TYPE_NODE: {
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE:
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE:
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: {
break;
}
}
@ -132,7 +143,9 @@ void BKE_viewer_path_foreach_id(LibraryForeachIDData *data, ViewerPath *viewer_p
break;
}
case VIEWER_PATH_ELEM_TYPE_MODIFIER:
case VIEWER_PATH_ELEM_TYPE_NODE: {
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE:
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE:
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: {
break;
}
}
@ -149,30 +162,39 @@ void BKE_viewer_path_id_remap(ViewerPath *viewer_path, const IDRemapper *mapping
break;
}
case VIEWER_PATH_ELEM_TYPE_MODIFIER:
case VIEWER_PATH_ELEM_TYPE_NODE: {
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE:
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE:
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: {
break;
}
}
}
}
template<typename T> static T *make_elem(const ViewerPathElemType type)
{
T *elem = MEM_cnew<T>(__func__);
elem->base.type = type;
return elem;
}
ViewerPathElem *BKE_viewer_path_elem_new(const ViewerPathElemType type)
{
switch (type) {
case VIEWER_PATH_ELEM_TYPE_ID: {
IDViewerPathElem *elem = MEM_cnew<IDViewerPathElem>(__func__);
elem->base.type = type;
return &elem->base;
return &make_elem<IDViewerPathElem>(type)->base;
}
case VIEWER_PATH_ELEM_TYPE_MODIFIER: {
ModifierViewerPathElem *elem = MEM_cnew<ModifierViewerPathElem>(__func__);
elem->base.type = type;
return &elem->base;
return &make_elem<ModifierViewerPathElem>(type)->base;
}
case VIEWER_PATH_ELEM_TYPE_NODE: {
NodeViewerPathElem *elem = MEM_cnew<NodeViewerPathElem>(__func__);
elem->base.type = type;
return &elem->base;
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: {
return &make_elem<GroupNodeViewerPathElem>(type)->base;
}
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: {
return &make_elem<SimulationZoneViewerPathElem>(type)->base;
}
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: {
return &make_elem<ViewerNodeViewerPathElem>(type)->base;
}
}
BLI_assert_unreachable();
@ -190,15 +212,30 @@ ModifierViewerPathElem *BKE_viewer_path_elem_new_modifier()
BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_MODIFIER));
}
NodeViewerPathElem *BKE_viewer_path_elem_new_node()
GroupNodeViewerPathElem *BKE_viewer_path_elem_new_group_node()
{
return reinterpret_cast<NodeViewerPathElem *>(
BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_NODE));
return reinterpret_cast<GroupNodeViewerPathElem *>(
BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_GROUP_NODE));
}
SimulationZoneViewerPathElem *BKE_viewer_path_elem_new_simulation_zone()
{
return reinterpret_cast<SimulationZoneViewerPathElem *>(
BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE));
}
ViewerNodeViewerPathElem *BKE_viewer_path_elem_new_viewer_node()
{
return reinterpret_cast<ViewerNodeViewerPathElem *>(
BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_VIEWER_NODE));
}
ViewerPathElem *BKE_viewer_path_elem_copy(const ViewerPathElem *src)
{
ViewerPathElem *dst = BKE_viewer_path_elem_new(ViewerPathElemType(src->type));
if (src->ui_name) {
dst->ui_name = BLI_strdup(src->ui_name);
}
switch (ViewerPathElemType(src->type)) {
case VIEWER_PATH_ELEM_TYPE_ID: {
const auto *old_elem = reinterpret_cast<const IDViewerPathElem *>(src);
@ -214,13 +251,22 @@ ViewerPathElem *BKE_viewer_path_elem_copy(const ViewerPathElem *src)
}
break;
}
case VIEWER_PATH_ELEM_TYPE_NODE: {
const auto *old_elem = reinterpret_cast<const NodeViewerPathElem *>(src);
auto *new_elem = reinterpret_cast<NodeViewerPathElem *>(dst);
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: {
const auto *old_elem = reinterpret_cast<const GroupNodeViewerPathElem *>(src);
auto *new_elem = reinterpret_cast<GroupNodeViewerPathElem *>(dst);
new_elem->node_id = old_elem->node_id;
break;
}
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: {
const auto *old_elem = reinterpret_cast<const SimulationZoneViewerPathElem *>(src);
auto *new_elem = reinterpret_cast<SimulationZoneViewerPathElem *>(dst);
new_elem->sim_output_node_id = old_elem->sim_output_node_id;
break;
}
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: {
const auto *old_elem = reinterpret_cast<const ViewerNodeViewerPathElem *>(src);
auto *new_elem = reinterpret_cast<ViewerNodeViewerPathElem *>(dst);
new_elem->node_id = old_elem->node_id;
if (old_elem->node_name != nullptr) {
new_elem->node_name = BLI_strdup(old_elem->node_name);
}
break;
}
}
@ -243,9 +289,19 @@ bool BKE_viewer_path_elem_equal(const ViewerPathElem *a, const ViewerPathElem *b
const auto *b_elem = reinterpret_cast<const ModifierViewerPathElem *>(b);
return StringRef(a_elem->modifier_name) == StringRef(b_elem->modifier_name);
}
case VIEWER_PATH_ELEM_TYPE_NODE: {
const auto *a_elem = reinterpret_cast<const NodeViewerPathElem *>(a);
const auto *b_elem = reinterpret_cast<const NodeViewerPathElem *>(b);
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: {
const auto *a_elem = reinterpret_cast<const GroupNodeViewerPathElem *>(a);
const auto *b_elem = reinterpret_cast<const GroupNodeViewerPathElem *>(b);
return a_elem->node_id == b_elem->node_id;
}
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: {
const auto *a_elem = reinterpret_cast<const SimulationZoneViewerPathElem *>(a);
const auto *b_elem = reinterpret_cast<const SimulationZoneViewerPathElem *>(b);
return a_elem->sim_output_node_id == b_elem->sim_output_node_id;
}
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: {
const auto *a_elem = reinterpret_cast<const ViewerNodeViewerPathElem *>(a);
const auto *b_elem = reinterpret_cast<const ViewerNodeViewerPathElem *>(b);
return a_elem->node_id == b_elem->node_id;
}
}
@ -255,7 +311,10 @@ bool BKE_viewer_path_elem_equal(const ViewerPathElem *a, const ViewerPathElem *b
void BKE_viewer_path_elem_free(ViewerPathElem *elem)
{
switch (ViewerPathElemType(elem->type)) {
case VIEWER_PATH_ELEM_TYPE_ID: {
case VIEWER_PATH_ELEM_TYPE_ID:
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE:
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE:
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: {
break;
}
case VIEWER_PATH_ELEM_TYPE_MODIFIER: {
@ -263,11 +322,9 @@ void BKE_viewer_path_elem_free(ViewerPathElem *elem)
MEM_SAFE_FREE(typed_elem->modifier_name);
break;
}
case VIEWER_PATH_ELEM_TYPE_NODE: {
auto *typed_elem = reinterpret_cast<NodeViewerPathElem *>(elem);
MEM_SAFE_FREE(typed_elem->node_name);
break;
}
}
if (elem->ui_name) {
MEM_freeN(elem->ui_name);
}
MEM_freeN(elem);
}

View File

@ -37,7 +37,7 @@ Object *parse_object_only(const ViewerPath &viewer_path);
struct ViewerPathForGeometryNodesViewer {
Object *object;
blender::StringRefNull modifier_name;
blender::Vector<int32_t> group_node_ids;
blender::Vector<const ViewerPathElem *> node_path;
int32_t viewer_node_id;
};
@ -65,7 +65,6 @@ bool exists_geometry_nodes_viewer(const ViewerPathForGeometryNodesViewer &parsed
* Checks if the node referenced by the viewer and its entire context is still active, i.e. some
* editor is showing it.
*/
bool is_active_geometry_nodes_viewer(const bContext &C,
const ViewerPathForGeometryNodesViewer &parsed_viewer_path);
bool is_active_geometry_nodes_viewer(const bContext &C, const ViewerPath &viewer_path);
} // namespace blender::ed::viewer_path

View File

@ -20,11 +20,7 @@ static void validate_viewer_paths(bContext &C, WorkSpace &workspace)
return;
}
const std::optional<blender::ed::viewer_path::ViewerPathForGeometryNodesViewer> parsed_path =
blender::ed::viewer_path::parse_geometry_nodes_viewer(workspace.viewer_path);
if (parsed_path.has_value() &&
blender::ed::viewer_path::is_active_geometry_nodes_viewer(C, *parsed_path))
{
if (blender::ed::viewer_path::is_active_geometry_nodes_viewer(C, workspace.viewer_path)) {
/* The current viewer path is still valid and active. */
return;
}

View File

@ -113,7 +113,7 @@ struct TreeDrawContext {
* Geometry nodes logs various data during execution. The logged data that corresponds to the
* currently drawn node tree can be retrieved from the log below.
*/
geo_log::GeoTreeLog *geo_tree_log = nullptr;
blender::Map<const TreeZone *, geo_log::GeoTreeLog *> geo_log_by_zone;
/**
* True if there is an active realtime compositor using the node tree, false otherwise.
*/
@ -1068,8 +1068,8 @@ static void create_inspection_string_for_geometry_socket(std::stringstream &ss,
}
}
static std::optional<std::string> create_socket_inspection_string(TreeDrawContext &tree_draw_ctx,
const bNodeSocket &socket)
static std::optional<std::string> create_socket_inspection_string(
geo_log::GeoTreeLog &geo_tree_log, const bNodeSocket &socket)
{
using namespace blender::nodes::geo_eval_log;
@ -1077,8 +1077,8 @@ static std::optional<std::string> create_socket_inspection_string(TreeDrawContex
return std::nullopt;
}
tree_draw_ctx.geo_tree_log->ensure_socket_values();
ValueLog *value_log = tree_draw_ctx.geo_tree_log->find_socket_value_log(socket);
geo_tree_log.ensure_socket_values();
ValueLog *value_log = geo_tree_log.find_socket_value_log(socket);
std::stringstream ss;
if (const geo_log::GenericValueLog *generic_value_log =
dynamic_cast<const geo_log::GenericValueLog *>(value_log))
@ -1131,7 +1131,8 @@ static char *node_socket_get_tooltip(const SpaceNode *snode,
TreeDrawContext tree_draw_ctx;
if (snode != nullptr) {
if (ntree.type == NTREE_GEOMETRY) {
tree_draw_ctx.geo_tree_log = geo_log::GeoModifierLog::get_tree_log_for_node_editor(*snode);
tree_draw_ctx.geo_log_by_zone =
geo_log::GeoModifierLog::get_tree_log_by_zone_for_node_editor(*snode);
}
}
@ -1144,13 +1145,22 @@ static char *node_socket_get_tooltip(const SpaceNode *snode,
}
}
if (ntree.type == NTREE_GEOMETRY && tree_draw_ctx.geo_tree_log != nullptr) {
geo_log::GeoTreeLog *geo_tree_log = [&]() -> geo_log::GeoTreeLog * {
const TreeZones *zones = ntree.zones();
if (!zones) {
return nullptr;
}
const TreeZone *zone = zones->get_zone_by_socket(socket);
return tree_draw_ctx.geo_log_by_zone.lookup_default(zone, nullptr);
}();
if (ntree.type == NTREE_GEOMETRY && geo_tree_log != nullptr) {
if (!output.str().empty()) {
output << ".\n\n";
}
std::optional<std::string> socket_inspection_str = create_socket_inspection_string(
tree_draw_ctx, socket);
*geo_tree_log, socket);
if (socket_inspection_str.has_value()) {
output << *socket_inspection_str;
}
@ -1738,9 +1748,18 @@ static void node_add_error_message_button(const TreeDrawContext &tree_draw_ctx,
return;
}
geo_log::GeoTreeLog *geo_tree_log = [&]() -> geo_log::GeoTreeLog * {
const TreeZones *zones = node.owner_tree().zones();
if (!zones) {
return nullptr;
}
const TreeZone *zone = zones->get_zone_by_node(node.identifier);
return tree_draw_ctx.geo_log_by_zone.lookup_default(zone, nullptr);
}();
Span<geo_log::NodeWarning> warnings;
if (tree_draw_ctx.geo_tree_log) {
geo_log::GeoNodeLog *node_log = tree_draw_ctx.geo_tree_log->nodes.lookup_ptr(node.identifier);
if (geo_tree_log) {
geo_log::GeoNodeLog *node_log = geo_tree_log->nodes.lookup_ptr(node.identifier);
if (node_log != nullptr) {
warnings = node_log->warnings;
}
@ -1778,7 +1797,15 @@ static void node_add_error_message_button(const TreeDrawContext &tree_draw_ctx,
static std::optional<std::chrono::nanoseconds> node_get_execution_time(
const TreeDrawContext &tree_draw_ctx, const bNodeTree &ntree, const bNode &node)
{
const geo_log::GeoTreeLog *tree_log = tree_draw_ctx.geo_tree_log;
geo_log::GeoTreeLog *tree_log = [&]() -> geo_log::GeoTreeLog * {
const TreeZones *zones = ntree.zones();
if (!zones) {
return nullptr;
}
const TreeZone *zone = zones->get_zone_by_node(node.identifier);
return tree_draw_ctx.geo_log_by_zone.lookup_default(zone, nullptr);
}();
if (tree_log == nullptr) {
return std::nullopt;
}
@ -1936,7 +1963,15 @@ static NodeExtraInfoRow row_from_used_named_attribute(
static std::optional<NodeExtraInfoRow> node_get_accessed_attributes_row(
TreeDrawContext &tree_draw_ctx, const bNode &node)
{
if (tree_draw_ctx.geo_tree_log == nullptr) {
geo_log::GeoTreeLog *geo_tree_log = [&]() -> geo_log::GeoTreeLog * {
const TreeZones *zones = node.owner_tree().zones();
if (!zones) {
return nullptr;
}
const TreeZone *zone = zones->get_zone_by_node(node.identifier);
return tree_draw_ctx.geo_log_by_zone.lookup_default(zone, nullptr);
}();
if (geo_tree_log == nullptr) {
return std::nullopt;
}
if (ELEM(node.type,
@ -1953,8 +1988,8 @@ static std::optional<NodeExtraInfoRow> node_get_accessed_attributes_row(
}
}
}
tree_draw_ctx.geo_tree_log->ensure_used_named_attributes();
geo_log::GeoNodeLog *node_log = tree_draw_ctx.geo_tree_log->nodes.lookup_ptr(node.identifier);
geo_tree_log->ensure_used_named_attributes();
geo_log::GeoNodeLog *node_log = geo_tree_log->nodes.lookup_ptr(node.identifier);
if (node_log == nullptr) {
return std::nullopt;
}
@ -1998,7 +2033,16 @@ static Vector<NodeExtraInfoRow> node_get_extra_info(TreeDrawContext &tree_draw_c
}
if (snode.edittree->type == NTREE_GEOMETRY) {
if (geo_log::GeoTreeLog *tree_log = tree_draw_ctx.geo_tree_log) {
geo_log::GeoTreeLog *tree_log = [&]() -> geo_log::GeoTreeLog * {
const TreeZones *tree_zones = node.owner_tree().zones();
if (!tree_zones) {
return nullptr;
}
const TreeZone *zone = tree_zones->get_zone_by_node(node.identifier);
return tree_draw_ctx.geo_log_by_zone.lookup_default(zone, nullptr);
}();
if (tree_log) {
tree_log->ensure_debug_messages();
const geo_log::GeoNodeLog *node_log = tree_log->nodes.lookup_ptr(node.identifier);
if (node_log != nullptr) {
@ -3126,7 +3170,7 @@ static void node_draw_zones(TreeDrawContext & /*tree_draw_ctx*/,
const SpaceNode &snode,
const bNodeTree &ntree)
{
const TreeZones *zones = bke::node_tree_zones::get_tree_zones(ntree);
const TreeZones *zones = ntree.zones();
if (zones == nullptr) {
return;
}
@ -3368,10 +3412,11 @@ static void draw_nodetree(const bContext &C,
TreeDrawContext tree_draw_ctx;
if (ntree.type == NTREE_GEOMETRY) {
tree_draw_ctx.geo_tree_log = geo_log::GeoModifierLog::get_tree_log_for_node_editor(*snode);
if (tree_draw_ctx.geo_tree_log != nullptr) {
tree_draw_ctx.geo_tree_log->ensure_node_warnings();
tree_draw_ctx.geo_tree_log->ensure_node_run_time();
tree_draw_ctx.geo_log_by_zone = geo_log::GeoModifierLog::get_tree_log_by_zone_for_node_editor(
*snode);
for (geo_log::GeoTreeLog *log : tree_draw_ctx.geo_log_by_zone.values()) {
log->ensure_node_warnings();
log->ensure_node_run_time();
}
const WorkSpace *workspace = CTX_wm_workspace(&C);
tree_draw_ctx.active_geometry_nodes_viewer = viewer_path::find_geometry_nodes_viewer(

View File

@ -18,6 +18,7 @@
#include "BKE_context.h"
#include "BKE_node_runtime.hh"
#include "BKE_node_tree_update.h"
#include "BKE_node_tree_zones.hh"
#include "BKE_object.h"
#include "RNA_access.h"
@ -41,6 +42,8 @@ using blender::nodes::geo_eval_log::GeometryAttributeInfo;
namespace blender::ed::space_node {
using namespace bke::node_tree_zones;
struct AttributeSearchData {
int32_t node_id;
char socket_identifier[MAX_NAME];
@ -69,23 +72,33 @@ static Vector<const GeometryAttributeInfo *> get_attribute_info_from_context(
BLI_assert_unreachable();
return {};
}
GeoTreeLog *tree_log = GeoModifierLog::get_tree_log_for_node_editor(*snode);
if (tree_log == nullptr) {
const TreeZones *tree_zones = node_tree->zones();
if (!tree_zones) {
return {};
}
tree_log->ensure_socket_values();
const Map<const TreeZone *, GeoTreeLog *> log_by_zone =
GeoModifierLog::get_tree_log_by_zone_for_node_editor(*snode);
/* For the attribute input node, collect attribute information from all nodes in the group. */
if (node->type == GEO_NODE_INPUT_NAMED_ATTRIBUTE) {
tree_log->ensure_existing_attributes();
Vector<const GeometryAttributeInfo *> attributes;
for (const GeometryAttributeInfo *attribute : tree_log->existing_attributes) {
if (bke::allow_procedural_attribute_access(attribute->name)) {
attributes.append(attribute);
for (GeoTreeLog *tree_log : log_by_zone.values()) {
tree_log->ensure_socket_values();
tree_log->ensure_existing_attributes();
for (const GeometryAttributeInfo *attribute : tree_log->existing_attributes) {
if (bke::allow_procedural_attribute_access(attribute->name)) {
attributes.append(attribute);
}
}
}
return attributes;
}
const TreeZone *zone = tree_zones->get_zone_by_node(node->identifier);
GeoTreeLog *tree_log = log_by_zone.lookup_default(zone, nullptr);
if (!tree_log) {
return {};
}
tree_log->ensure_socket_values();
GeoNodeLog *node_log = tree_log->nodes.lookup_ptr(node->identifier);
if (node_log == nullptr) {
return {};

View File

@ -8,6 +8,7 @@
#include "BKE_context.h"
#include "BKE_main.h"
#include "BKE_node_runtime.hh"
#include "BKE_node_tree_zones.hh"
#include "BKE_workspace.h"
#include "BLI_listbase.h"
@ -22,6 +23,8 @@
namespace blender::ed::viewer_path {
using namespace bke::node_tree_zones;
static void viewer_path_for_geometry_node(const SpaceNode &snode,
const bNode &node,
ViewerPath &r_dst)
@ -55,27 +58,56 @@ static void viewer_path_for_geometry_node(const SpaceNode &snode,
modifier = nmd;
}
}
if (modifier != nullptr) {
ModifierViewerPathElem *modifier_elem = BKE_viewer_path_elem_new_modifier();
modifier_elem->modifier_name = BLI_strdup(modifier->modifier.name);
BLI_addtail(&r_dst.path, modifier_elem);
if (modifier == nullptr) {
return;
}
ModifierViewerPathElem *modifier_elem = BKE_viewer_path_elem_new_modifier();
modifier_elem->modifier_name = BLI_strdup(modifier->modifier.name);
BLI_addtail(&r_dst.path, modifier_elem);
Vector<const bNodeTreePath *, 16> tree_path = snode.treepath;
for (const int i : tree_path.index_range().drop_back(1)) {
bNodeTree *tree = tree_path[i]->nodetree;
/* The tree path contains the name of the node but not its ID. */
const bNode *node = nodeFindNodebyName(tree_path[i]->nodetree, tree_path[i + 1]->node_name);
const char *node_name = tree_path[i + 1]->node_name;
const bNode *node = nodeFindNodebyName(tree, node_name);
/* The name in the tree path should match a group node in the tree. */
BLI_assert(node != nullptr);
NodeViewerPathElem *node_elem = BKE_viewer_path_elem_new_node();
tree->ensure_topology_cache();
const TreeZones *tree_zones = tree->zones();
if (!tree_zones) {
return;
}
const Vector<const TreeZone *> zone_stack = tree_zones->get_zone_stack_for_node(
node->identifier);
for (const TreeZone *zone : zone_stack) {
SimulationZoneViewerPathElem *node_elem = BKE_viewer_path_elem_new_simulation_zone();
node_elem->sim_output_node_id = zone->output_node->identifier;
BLI_addtail(&r_dst.path, node_elem);
}
GroupNodeViewerPathElem *node_elem = BKE_viewer_path_elem_new_group_node();
node_elem->node_id = node->identifier;
node_elem->node_name = BLI_strdup(node->name);
node_elem->base.ui_name = BLI_strdup(node->name);
BLI_addtail(&r_dst.path, node_elem);
}
NodeViewerPathElem *viewer_node_elem = BKE_viewer_path_elem_new_node();
snode.edittree->ensure_topology_cache();
const TreeZones *tree_zones = snode.edittree->zones();
if (!tree_zones) {
return;
}
const Vector<const TreeZone *> zone_stack = tree_zones->get_zone_stack_for_node(node.identifier);
for (const TreeZone *zone : zone_stack) {
SimulationZoneViewerPathElem *node_elem = BKE_viewer_path_elem_new_simulation_zone();
node_elem->sim_output_node_id = zone->output_node->identifier;
BLI_addtail(&r_dst.path, node_elem);
}
ViewerNodeViewerPathElem *viewer_node_elem = BKE_viewer_path_elem_new_viewer_node();
viewer_node_elem->node_id = node.identifier;
viewer_node_elem->node_name = BLI_strdup(node.name);
viewer_node_elem->base.ui_name = BLI_strdup(node.name);
BLI_addtail(&r_dst.path, viewer_node_elem);
}
@ -185,16 +217,21 @@ std::optional<ViewerPathForGeometryNodesViewer> parse_geometry_nodes_viewer(
return std::nullopt;
}
remaining_elems = remaining_elems.drop_front(1);
Vector<int32_t> node_ids;
for (const ViewerPathElem *elem : remaining_elems) {
if (elem->type != VIEWER_PATH_ELEM_TYPE_NODE) {
Vector<const ViewerPathElem *> node_path;
for (const ViewerPathElem *elem : remaining_elems.drop_back(1)) {
if (!ELEM(elem->type, VIEWER_PATH_ELEM_TYPE_GROUP_NODE, VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE))
{
return std::nullopt;
}
const int32_t node_id = reinterpret_cast<const NodeViewerPathElem *>(elem)->node_id;
node_ids.append(node_id);
node_path.append(elem);
}
const int32_t viewer_node_id = node_ids.pop_last();
return ViewerPathForGeometryNodesViewer{root_ob, modifier_name, node_ids, viewer_node_id};
const ViewerPathElem *last_elem = remaining_elems.last();
if (last_elem->type != VIEWER_PATH_ELEM_TYPE_VIEWER_NODE) {
return std::nullopt;
}
const int32_t viewer_node_id =
reinterpret_cast<const ViewerNodeViewerPathElem *>(last_elem)->node_id;
return ViewerPathForGeometryNodesViewer{root_ob, modifier_name, node_path, viewer_node_id};
}
bool exists_geometry_nodes_viewer(const ViewerPathForGeometryNodesViewer &parsed_viewer_path)
@ -217,81 +254,72 @@ bool exists_geometry_nodes_viewer(const ViewerPathForGeometryNodesViewer &parsed
return false;
}
const bNodeTree *ngroup = modifier->node_group;
ngroup->ensure_topology_cache();
for (const int32_t group_node_id : parsed_viewer_path.group_node_ids) {
const bNode *group_node = nullptr;
for (const bNode *node : ngroup->group_nodes()) {
if (node->identifier != group_node_id) {
continue;
const TreeZone *zone = nullptr;
for (const ViewerPathElem *path_elem : parsed_viewer_path.node_path) {
ngroup->ensure_topology_cache();
const TreeZones *tree_zones = ngroup->zones();
switch (path_elem->type) {
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: {
const auto &typed_elem = *reinterpret_cast<const SimulationZoneViewerPathElem *>(
path_elem);
const TreeZone *next_zone = tree_zones->get_zone_by_node(typed_elem.sim_output_node_id);
if (next_zone == nullptr) {
return false;
}
if (next_zone->parent_zone != zone) {
return false;
}
zone = next_zone;
break;
}
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: {
const auto &typed_elem = *reinterpret_cast<const GroupNodeViewerPathElem *>(path_elem);
const bNode *group_node = ngroup->node_by_id(typed_elem.node_id);
if (group_node == nullptr) {
return false;
}
const TreeZone *parent_zone = tree_zones->get_zone_by_node(typed_elem.node_id);
if (parent_zone != zone) {
return false;
}
if (group_node->id == nullptr) {
return false;
}
ngroup = reinterpret_cast<const bNodeTree *>(group_node->id);
zone = nullptr;
break;
}
default: {
BLI_assert_unreachable();
}
group_node = node;
break;
}
if (group_node == nullptr) {
return false;
}
if (group_node->id == nullptr) {
return false;
}
ngroup = reinterpret_cast<const bNodeTree *>(group_node->id);
}
const bNode *viewer_node = nullptr;
for (const bNode *node : ngroup->nodes_by_type("GeometryNodeViewer")) {
if (node->identifier != parsed_viewer_path.viewer_node_id) {
continue;
}
viewer_node = node;
break;
}
const bNode *viewer_node = ngroup->node_by_id(parsed_viewer_path.viewer_node_id);
if (viewer_node == nullptr) {
return false;
}
return true;
}
static bool viewer_path_matches_node_editor_path(
const SpaceNode &snode, const ViewerPathForGeometryNodesViewer &parsed_viewer_path)
{
Vector<const bNodeTreePath *, 16> tree_path = snode.treepath;
if (tree_path.size() != parsed_viewer_path.group_node_ids.size() + 1) {
const TreeZones *tree_zones = ngroup->zones();
if (tree_zones == nullptr) {
return false;
}
for (const int i : parsed_viewer_path.group_node_ids.index_range()) {
const bNode *node = tree_path[i]->nodetree->node_by_id(parsed_viewer_path.group_node_ids[i]);
if (!node) {
return false;
}
if (!STREQ(node->name, tree_path[i + 1]->node_name)) {
return false;
}
if (tree_zones->get_zone_by_node(viewer_node->identifier) != zone) {
return false;
}
return true;
}
bool is_active_geometry_nodes_viewer(const bContext &C,
const ViewerPathForGeometryNodesViewer &parsed_viewer_path)
bool is_active_geometry_nodes_viewer(const bContext &C, const ViewerPath &viewer_path)
{
const NodesModifierData *modifier = nullptr;
LISTBASE_FOREACH (const ModifierData *, md, &parsed_viewer_path.object->modifiers) {
if (md->name != parsed_viewer_path.modifier_name) {
continue;
}
if (md->type != eModifierType_Nodes) {
return false;
}
if ((md->mode & eModifierMode_Realtime) == 0) {
return false;
}
modifier = reinterpret_cast<const NodesModifierData *>(md);
break;
}
if (modifier == nullptr) {
if (BLI_listbase_is_empty(&viewer_path.path)) {
return false;
}
if (modifier->node_group == nullptr) {
const ViewerPathElem *last_elem = static_cast<ViewerPathElem *>(viewer_path.path.last);
if (last_elem->type != VIEWER_PATH_ELEM_TYPE_VIEWER_NODE) {
return false;
}
const bool modifier_is_active = modifier->modifier.flag & eModifierFlag_Active;
const int32_t viewer_node_id =
reinterpret_cast<const ViewerNodeViewerPathElem *>(last_elem)->node_id;
const Main *bmain = CTX_data_main(&C);
const wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
@ -315,30 +343,26 @@ bool is_active_geometry_nodes_viewer(const bContext &C,
continue;
}
const SpaceNode &snode = *reinterpret_cast<const SpaceNode *>(sl);
if (!modifier_is_active) {
if (!(snode.flag & SNODE_PIN)) {
/* Node tree has to be pinned when the modifier is not active. */
continue;
}
}
if (snode.id != &parsed_viewer_path.object->id) {
if (snode.edittree == nullptr) {
continue;
}
if (snode.nodetree != modifier->node_group) {
if (snode.edittree->type != NTREE_GEOMETRY) {
continue;
}
if (!viewer_path_matches_node_editor_path(snode, parsed_viewer_path)) {
continue;
}
const bNodeTree *ngroup = snode.edittree;
ngroup->ensure_topology_cache();
const bNode *viewer_node = ngroup->node_by_id(parsed_viewer_path.viewer_node_id);
snode.edittree->ensure_topology_cache();
const bNode *viewer_node = snode.edittree->node_by_id(viewer_node_id);
if (viewer_node == nullptr) {
continue;
}
if (!(viewer_node->flag & NODE_DO_OUTPUT)) {
continue;
}
ViewerPath tmp_viewer_path{};
BLI_SCOPED_DEFER([&]() { BKE_viewer_path_clear(&tmp_viewer_path); });
viewer_path_for_geometry_node(snode, *viewer_node, tmp_viewer_path);
if (!BKE_viewer_path_equal(&viewer_path, &tmp_viewer_path)) {
continue;
}
return true;
}
}

View File

@ -30,7 +30,13 @@ namespace blender::bke {
class bNodeTreeRuntime;
class bNodeRuntime;
class bNodeSocketRuntime;
class bNodeZones;
class bNodeZone;
} // namespace blender::bke
namespace blender::bke::node_tree_zones {
class TreeZones;
struct TreeZone;
} // namespace blender::bke::node_tree_zones
using NodeDeclarationHandle = blender::nodes::NodeDeclaration;
using SocketDeclarationHandle = blender::nodes::SocketDeclaration;
using bNodeTreeRuntimeHandle = blender::bke::bNodeTreeRuntime;
@ -677,6 +683,8 @@ typedef struct bNodeTree {
blender::Span<const bNodePanel *> panels() const;
blender::MutableSpan<bNodePanel *> panels_for_write();
/** Zones in the node tree. Currently there are only simulation zones in geometry nodes. */
const blender::bke::node_tree_zones::TreeZones *zones() const;
#endif
} bNodeTree;

View File

@ -12,13 +12,16 @@ struct ID;
typedef enum ViewerPathElemType {
VIEWER_PATH_ELEM_TYPE_ID = 0,
VIEWER_PATH_ELEM_TYPE_MODIFIER = 1,
VIEWER_PATH_ELEM_TYPE_NODE = 2,
VIEWER_PATH_ELEM_TYPE_GROUP_NODE = 2,
VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE = 3,
VIEWER_PATH_ELEM_TYPE_VIEWER_NODE = 4,
} ViewerPathElemType;
typedef struct ViewerPathElem {
struct ViewerPathElem *next, *prev;
int type;
char _pad[4];
char *ui_name;
} ViewerPathElem;
typedef struct IDViewerPathElem {
@ -31,18 +34,26 @@ typedef struct ModifierViewerPathElem {
char *modifier_name;
} ModifierViewerPathElem;
typedef struct NodeViewerPathElem {
typedef struct GroupNodeViewerPathElem {
ViewerPathElem base;
int32_t node_id;
char _pad1[4];
} GroupNodeViewerPathElem;
/**
* The name of the node with the identifier. Not used to lookup nodes, only for display
* in the UI. Still stored here to avoid looking up the name for every redraw.
*/
char *node_name;
} NodeViewerPathElem;
typedef struct SimulationZoneViewerPathElem {
ViewerPathElem base;
int32_t sim_output_node_id;
char _pad1[4];
} SimulationZoneViewerPathElem;
typedef struct ViewerNodeViewerPathElem {
ViewerPathElem base;
int32_t node_id;
char _pad1[4];
} ViewerNodeViewerPathElem;
typedef struct ViewerPath {
/** List of #ViewerPathElem. */

View File

@ -3331,8 +3331,12 @@ static StructRNA *rna_viewer_path_elem_refine(PointerRNA *ptr)
return &RNA_IDViewerPathElem;
case VIEWER_PATH_ELEM_TYPE_MODIFIER:
return &RNA_ModifierViewerPathElem;
case VIEWER_PATH_ELEM_TYPE_NODE:
return &RNA_NodeViewerPathElem;
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE:
return &RNA_GroupNodeViewerPathElem;
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE:
return &RNA_SimulationZoneViewerPathElem;
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE:
return &RNA_ViewerNodeViewerPathElem;
}
BLI_assert_unreachable();
return nullptr;
@ -8049,7 +8053,9 @@ static void rna_def_spreadsheet_row_filter(BlenderRNA *brna)
static const EnumPropertyItem viewer_path_elem_type_items[] = {
{VIEWER_PATH_ELEM_TYPE_ID, "ID", ICON_NONE, "ID", ""},
{VIEWER_PATH_ELEM_TYPE_MODIFIER, "MODIFIER", ICON_NONE, "Modifier", ""},
{VIEWER_PATH_ELEM_TYPE_NODE, "NODE", ICON_NONE, "Node", ""},
{VIEWER_PATH_ELEM_TYPE_GROUP_NODE, "GROUP_NODE", ICON_NONE, "Group Node", ""},
{VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE, "SIMULATION_ZONE", ICON_NONE, "Simulation Zone", ""},
{VIEWER_PATH_ELEM_TYPE_VIEWER_NODE, "VIEWER_NODE", ICON_NONE, "Viewer Node", ""},
{0, nullptr, 0, nullptr, nullptr},
};
@ -8066,6 +8072,11 @@ static void rna_def_viewer_path_elem(BlenderRNA *brna)
RNA_def_property_enum_items(prop, viewer_path_elem_type_items);
RNA_def_property_ui_text(prop, "Type", "Type of the path element");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "ui_name", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(
prop, "UI Name", "Name that can be displayed in the UI for this element");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
static void rna_def_id_viewer_path_elem(BlenderRNA *brna)
@ -8090,15 +8101,37 @@ static void rna_def_modifier_viewer_path_elem(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Modifier Name", "");
}
static void rna_def_node_viewer_path_elem(BlenderRNA *brna)
static void rna_def_group_node_viewer_path_elem(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "NodeViewerPathElem", "ViewerPathElem");
srna = RNA_def_struct(brna, "GroupNodeViewerPathElem", "ViewerPathElem");
prop = RNA_def_property(srna, "node_name", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Node Name", "");
prop = RNA_def_property(srna, "node_id", PROP_INT, PROP_NONE);
RNA_def_property_ui_text(prop, "Node ID", "");
}
static void rna_def_simulation_zone_viewer_path_elem(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "SimulationZoneViewerPathElem", "ViewerPathElem");
prop = RNA_def_property(srna, "sim_output_node_id", PROP_INT, PROP_NONE);
RNA_def_property_ui_text(prop, "Simulation Output Node ID", "");
}
static void rna_def_viewer_node_viewer_path_elem(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "ViewerNodeViewerPathElem", "ViewerPathElem");
prop = RNA_def_property(srna, "node_id", PROP_INT, PROP_NONE);
RNA_def_property_ui_text(prop, "Node ID", "");
}
static void rna_def_viewer_path(BlenderRNA *brna)
@ -8109,7 +8142,9 @@ static void rna_def_viewer_path(BlenderRNA *brna)
rna_def_viewer_path_elem(brna);
rna_def_id_viewer_path_elem(brna);
rna_def_modifier_viewer_path_elem(brna);
rna_def_node_viewer_path_elem(brna);
rna_def_group_node_viewer_path_elem(brna);
rna_def_simulation_zone_viewer_path_elem(brna);
rna_def_viewer_node_viewer_path_elem(brna);
srna = RNA_def_struct(brna, "ViewerPath", nullptr);
RNA_def_struct_ui_text(srna, "Viewer Path", "Path to data that is viewed");

View File

@ -424,31 +424,14 @@ void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd)
namespace blender {
static const lf::FunctionNode *find_viewer_lf_node(const bNode &viewer_bnode)
{
if (const nodes::GeometryNodesLazyFunctionGraphInfo *lf_graph_info =
nodes::ensure_geometry_nodes_lazy_function_graph(viewer_bnode.owner_tree()))
{
return lf_graph_info->mapping.viewer_node_map.lookup_default(&viewer_bnode, nullptr);
}
return nullptr;
}
static const lf::FunctionNode *find_group_lf_node(const bNode &group_bnode)
{
if (const nodes::GeometryNodesLazyFunctionGraphInfo *lf_graph_info =
nodes::ensure_geometry_nodes_lazy_function_graph(group_bnode.owner_tree()))
{
return lf_graph_info->mapping.group_node_map.lookup_default(&group_bnode, nullptr);
}
return nullptr;
}
static void find_side_effect_nodes_for_viewer_path(
const ViewerPath &viewer_path,
const NodesModifierData &nmd,
const ModifierEvalContext &ctx,
MultiValueMap<ComputeContextHash, const lf::FunctionNode *> &r_side_effect_nodes)
{
using namespace bke::node_tree_zones;
const std::optional<ed::viewer_path::ViewerPathForGeometryNodesViewer> parsed_path =
ed::viewer_path::parse_geometry_nodes_viewer(viewer_path);
if (!parsed_path.has_value()) {
@ -464,45 +447,100 @@ static void find_side_effect_nodes_for_viewer_path(
ComputeContextBuilder compute_context_builder;
compute_context_builder.push<bke::ModifierComputeContext>(parsed_path->modifier_name);
/* Write side effect nodes to a new map and only if everything succeeds, move the nodes to the
* caller. This is easier than changing r_side_effect_nodes directly and then undoing changes in
* case of errors. */
MultiValueMap<ComputeContextHash, const lf::FunctionNode *> local_side_effect_nodes;
const bNodeTree *group = nmd.node_group;
Stack<const bNode *> group_node_stack;
for (const int32_t group_node_id : parsed_path->group_node_ids) {
const bNode *found_node = group->node_by_id(group_node_id);
if (found_node == nullptr) {
const TreeZone *zone = nullptr;
for (const ViewerPathElem *elem : parsed_path->node_path) {
const TreeZones *tree_zones = group->zones();
if (tree_zones == nullptr) {
return;
}
if (found_node->id == nullptr) {
const auto *lf_graph_info = nodes::ensure_geometry_nodes_lazy_function_graph(*group);
if (lf_graph_info == nullptr) {
return;
}
if (found_node->is_muted()) {
return;
switch (elem->type) {
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: {
const auto &typed_elem = *reinterpret_cast<const SimulationZoneViewerPathElem *>(elem);
const TreeZone *next_zone = tree_zones->get_zone_by_node(typed_elem.sim_output_node_id);
if (next_zone == nullptr) {
return;
}
if (next_zone->parent_zone != zone) {
return;
}
const lf::FunctionNode *lf_zone_node = lf_graph_info->mapping.zone_node_map.lookup_default(
next_zone, nullptr);
if (lf_zone_node == nullptr) {
return;
}
local_side_effect_nodes.add(compute_context_builder.hash(), lf_zone_node);
compute_context_builder.push<bke::SimulationZoneComputeContext>(*next_zone->output_node);
zone = next_zone;
break;
}
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: {
const auto &typed_elem = *reinterpret_cast<const GroupNodeViewerPathElem *>(elem);
const bNode *node = group->node_by_id(typed_elem.node_id);
if (node == nullptr) {
return;
}
if (node->id == nullptr) {
return;
}
if (node->is_muted()) {
return;
}
if (zone != tree_zones->get_zone_by_node(node->identifier)) {
return;
}
const lf::FunctionNode *lf_group_node =
lf_graph_info->mapping.group_node_map.lookup_default(node, nullptr);
if (lf_group_node == nullptr) {
return;
}
local_side_effect_nodes.add(compute_context_builder.hash(), lf_group_node);
compute_context_builder.push<bke::NodeGroupComputeContext>(*node);
group = reinterpret_cast<const bNodeTree *>(node->id);
zone = nullptr;
break;
}
default: {
BLI_assert_unreachable();
return;
}
}
group_node_stack.push(found_node);
group = reinterpret_cast<bNodeTree *>(found_node->id);
compute_context_builder.push<bke::NodeGroupComputeContext>(*found_node);
}
const bNode *found_viewer_node = group->node_by_id(parsed_path->viewer_node_id);
if (found_viewer_node == nullptr) {
return;
}
const lf::FunctionNode *lf_viewer_node = find_viewer_lf_node(*found_viewer_node);
const auto *lf_graph_info = nodes::ensure_geometry_nodes_lazy_function_graph(*group);
if (lf_graph_info == nullptr) {
return;
}
const TreeZones *tree_zones = group->zones();
if (tree_zones == nullptr) {
return;
}
if (tree_zones->get_zone_by_node(found_viewer_node->identifier) != zone) {
return;
}
const lf::FunctionNode *lf_viewer_node = lf_graph_info->mapping.viewer_node_map.lookup_default(
found_viewer_node, nullptr);
if (lf_viewer_node == nullptr) {
return;
}
local_side_effect_nodes.add(compute_context_builder.hash(), lf_viewer_node);
/* Not only mark the viewer node as having side effects, but also all group nodes it is contained
* in. */
r_side_effect_nodes.add_non_duplicates(compute_context_builder.hash(), lf_viewer_node);
compute_context_builder.pop();
while (!compute_context_builder.is_empty()) {
const lf::FunctionNode *lf_group_node = find_group_lf_node(*group_node_stack.pop());
if (lf_group_node == nullptr) {
return;
}
r_side_effect_nodes.add_non_duplicates(compute_context_builder.hash(), lf_group_node);
compute_context_builder.pop();
/* Successfully found all compute contexts for the viewer. */
for (const auto item : local_side_effect_nodes.items()) {
r_side_effect_nodes.add_multiple(item.key, item.value);
}
}
@ -550,11 +588,11 @@ static void find_socket_log_contexts(const NodesModifierData &nmd,
const SpaceLink *sl = static_cast<SpaceLink *>(area->spacedata.first);
if (sl->spacetype == SPACE_NODE) {
const SpaceNode &snode = *reinterpret_cast<const SpaceNode *>(sl);
if (const std::optional<ComputeContextHash> hash =
geo_log::GeoModifierLog::get_compute_context_hash_for_node_editor(
snode, nmd.modifier.name))
{
r_socket_log_contexts.add(*hash);
const Map<const bke::node_tree_zones::TreeZone *, ComputeContextHash> hash_by_zone =
geo_log::GeoModifierLog::get_context_hash_by_zone_for_node_editor(snode,
nmd.modifier.name);
for (const ComputeContextHash &hash : hash_by_zone.values()) {
r_socket_log_contexts.add(hash);
}
}
}

View File

@ -28,6 +28,7 @@
#include "BLI_compute_context.hh"
#include "BKE_node_tree_zones.hh"
#include "BKE_simulation_state.hh"
struct Object;
@ -175,7 +176,7 @@ struct GeometryNodeLazyFunctionGraphMapping {
*/
Map<const bNode *, const lf::FunctionNode *> group_node_map;
Map<const bNode *, const lf::FunctionNode *> viewer_node_map;
Map<const bNode *, const lf::FunctionNode *> sim_output_node_map;
Map<const bke::node_tree_zones::TreeZone *, const lf::FunctionNode *> zone_node_map;
/* Indexed by #bNodeSocket::index_in_all_outputs. */
Array<int> lf_input_index_for_output_bsocket_usage;
@ -190,29 +191,9 @@ struct GeometryNodeLazyFunctionGraphMapping {
*/
struct GeometryNodesLazyFunctionGraphInfo {
/**
* Allocator used for many things contained in this struct.
* Contains resources that need to be freed when the graph is not needed anymore.
*/
LinearAllocator<> allocator;
/**
* Many nodes are implemented as multi-functions. So this contains a mapping from nodes to their
* corresponding multi-functions.
*/
std::unique_ptr<NodeMultiFunctions> node_multi_functions;
/**
* Many lazy-functions are build for the lazy-function graph. Since the graph does not own them,
* we have to keep track of them separately.
*/
Vector<std::unique_ptr<LazyFunction>> functions;
/**
* Debug info that has to be destructed when the graph is not used anymore.
*/
Vector<std::unique_ptr<lf::DummyDebugInfo>> dummy_debug_infos_;
/**
* Many sockets have default values. Since those are not owned by the lazy-function graph, we
* have to keep track of them separately. This only owns the values, the memory is owned by the
* allocator above.
*/
Vector<GMutablePointer> values_to_destruct;
ResourceScope scope;
/**
* The actual lazy-function graph.
*/
@ -226,9 +207,6 @@ struct GeometryNodesLazyFunctionGraphInfo {
* This can be used as a simple heuristic for the complexity of the node group.
*/
int num_inline_nodes_approximate = 0;
GeometryNodesLazyFunctionGraphInfo();
~GeometryNodesLazyFunctionGraphInfo();
};
/**

View File

@ -37,6 +37,7 @@
#include "BKE_attribute.h"
#include "BKE_geometry_set.hh"
#include "BKE_node_tree_zones.hh"
#include "BKE_viewer_path.h"
#include "FN_field.hh"
@ -333,9 +334,11 @@ class GeoModifierLog {
/**
* Utility accessor to logged data.
*/
static std::optional<ComputeContextHash> get_compute_context_hash_for_node_editor(
const SpaceNode &snode, StringRefNull modifier_name);
static GeoTreeLog *get_tree_log_for_node_editor(const SpaceNode &snode);
static Map<const bke::node_tree_zones::TreeZone *, ComputeContextHash>
get_context_hash_by_zone_for_node_editor(const SpaceNode &snode, StringRefNull modifier_name);
static Map<const bke::node_tree_zones::TreeZone *, GeoTreeLog *>
get_tree_log_by_zone_for_node_editor(const SpaceNode &snode);
static const ViewerNodeLog *find_viewer_node_log_for_path(const ViewerPath &viewer_path);
};

File diff suppressed because it is too large Load Diff

View File

@ -21,6 +21,7 @@ namespace blender::nodes::geo_eval_log {
using fn::FieldInput;
using fn::FieldInputs;
using namespace bke::node_tree_zones;
GenericValueLog::~GenericValueLog()
{
@ -518,46 +519,82 @@ static std::optional<ObjectAndModifier> get_modifier_for_node_editor(const Space
return ObjectAndModifier{object, used_modifier};
}
std::optional<ComputeContextHash> GeoModifierLog::get_compute_context_hash_for_node_editor(
const SpaceNode &snode, const StringRefNull modifier_name)
static void find_tree_zone_hash_recursive(
const TreeZone &zone,
ComputeContextBuilder &compute_context_builder,
Map<const TreeZone *, ComputeContextHash> &r_hash_by_zone)
{
Vector<const bNodeTreePath *> tree_path = snode.treepath;
if (tree_path.is_empty()) {
return std::nullopt;
compute_context_builder.push<bke::SimulationZoneComputeContext>(*zone.output_node);
r_hash_by_zone.add_new(&zone, compute_context_builder.hash());
for (const TreeZone *child_zone : zone.child_zones) {
find_tree_zone_hash_recursive(*child_zone, compute_context_builder, r_hash_by_zone);
}
ComputeContextBuilder compute_context_builder;
compute_context_builder.push<bke::ModifierComputeContext>(modifier_name);
for (const int i : tree_path.index_range().drop_back(1)) {
/* The tree path contains the name of the node but not its ID. */
const bNode *node = nodeFindNodebyName(tree_path[i]->nodetree, tree_path[i + 1]->node_name);
if (node == nullptr) {
/* The current tree path is invalid, probably because some parent group node has been
* deleted. */
return std::nullopt;
}
compute_context_builder.push<bke::NodeGroupComputeContext>(*node);
}
return compute_context_builder.hash();
compute_context_builder.pop();
}
GeoTreeLog *GeoModifierLog::get_tree_log_for_node_editor(const SpaceNode &snode)
Map<const TreeZone *, ComputeContextHash> GeoModifierLog::get_context_hash_by_zone_for_node_editor(
const SpaceNode &snode, StringRefNull modifier_name)
{
const Vector<const bNodeTreePath *> tree_path = snode.treepath;
if (tree_path.is_empty()) {
return {};
}
ComputeContextBuilder compute_context_builder;
compute_context_builder.push<bke::ModifierComputeContext>(modifier_name);
for (const int i : tree_path.index_range().drop_back(1)) {
bNodeTree *tree = tree_path[i]->nodetree;
const char *group_node_name = tree_path[i + 1]->node_name;
const bNode *group_node = nodeFindNodebyName(tree, group_node_name);
if (group_node == nullptr) {
return {};
}
const TreeZones *tree_zones = tree->zones();
if (tree_zones == nullptr) {
return {};
}
const Vector<const TreeZone *> zone_stack = tree_zones->get_zone_stack_for_node(
group_node->identifier);
for (const TreeZone *zone : zone_stack) {
compute_context_builder.push<bke::SimulationZoneComputeContext>(*zone->output_node);
}
compute_context_builder.push<bke::NodeGroupComputeContext>(*group_node);
}
const TreeZones *tree_zones = snode.edittree->zones();
if (tree_zones == nullptr) {
return {};
}
Map<const TreeZone *, ComputeContextHash> hash_by_zone;
hash_by_zone.add_new(nullptr, compute_context_builder.hash());
for (const TreeZone *zone : tree_zones->root_zones) {
find_tree_zone_hash_recursive(*zone, compute_context_builder, hash_by_zone);
}
return hash_by_zone;
}
Map<const TreeZone *, GeoTreeLog *> GeoModifierLog::get_tree_log_by_zone_for_node_editor(
const SpaceNode &snode)
{
std::optional<ObjectAndModifier> object_and_modifier = get_modifier_for_node_editor(snode);
if (!object_and_modifier) {
return nullptr;
return {};
}
GeoModifierLog *modifier_log = static_cast<GeoModifierLog *>(
object_and_modifier->nmd->runtime_eval_log);
if (modifier_log == nullptr) {
return nullptr;
return {};
}
if (const std::optional<ComputeContextHash> hash =
GeoModifierLog::get_compute_context_hash_for_node_editor(
snode, object_and_modifier->nmd->modifier.name))
{
return &modifier_log->get_tree_log(*hash);
const Map<const TreeZone *, ComputeContextHash> hash_by_zone =
GeoModifierLog::get_context_hash_by_zone_for_node_editor(
snode, object_and_modifier->nmd->modifier.name);
Map<const TreeZone *, GeoTreeLog *> log_by_zone;
for (const auto item : hash_by_zone.items()) {
GeoTreeLog &tree_log = modifier_log->get_tree_log(item.value);
log_by_zone.add(item.key, &tree_log);
}
return nullptr;
return log_by_zone;
}
const ViewerNodeLog *GeoModifierLog::find_viewer_node_log_for_path(const ViewerPath &viewer_path)
@ -587,8 +624,24 @@ const ViewerNodeLog *GeoModifierLog::find_viewer_node_log_for_path(const ViewerP
ComputeContextBuilder compute_context_builder;
compute_context_builder.push<bke::ModifierComputeContext>(parsed_path->modifier_name);
for (const int32_t group_node_id : parsed_path->group_node_ids) {
compute_context_builder.push<bke::NodeGroupComputeContext>(group_node_id);
for (const ViewerPathElem *elem : parsed_path->node_path) {
switch (elem->type) {
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: {
const auto &typed_elem = *reinterpret_cast<const GroupNodeViewerPathElem *>(elem);
compute_context_builder.push<bke::NodeGroupComputeContext>(typed_elem.node_id);
break;
}
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: {
const auto &typed_elem = *reinterpret_cast<const SimulationZoneViewerPathElem *>(elem);
compute_context_builder.push<bke::SimulationZoneComputeContext>(
typed_elem.sim_output_node_id);
break;
}
default: {
BLI_assert_unreachable();
break;
}
}
}
const ComputeContextHash context_hash = compute_context_builder.hash();
nodes::geo_eval_log::GeoTreeLog &tree_log = modifier_log->get_tree_log(context_hash);