Add Chromium-only Blender WebEngine parity work
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
/* SPDX-FileCopyrightText: 2013 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup depsgraph
|
||||
*/
|
||||
|
||||
#include "intern/debug/deg_debug.h"
|
||||
|
||||
#include "BLI_console.h"
|
||||
#include "BLI_hash.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_time.h"
|
||||
|
||||
#include "BKE_global.hh"
|
||||
|
||||
namespace blender::deg {
|
||||
|
||||
DepsgraphDebug::DepsgraphDebug() : flags(G.debug), graph_evaluation_start_time_(0) {}
|
||||
|
||||
bool DepsgraphDebug::do_time_debug() const
|
||||
{
|
||||
return ((G.debug & G_DEBUG_DEPSGRAPH_TIME) != 0);
|
||||
}
|
||||
|
||||
void DepsgraphDebug::begin_graph_evaluation()
|
||||
{
|
||||
const double current_time = BLI_time_now_seconds();
|
||||
|
||||
graph_evaluation_start_time_ = current_time;
|
||||
}
|
||||
|
||||
void DepsgraphDebug::end_graph_evaluation()
|
||||
{
|
||||
const double graph_eval_end_time = BLI_time_now_seconds();
|
||||
graph_evaluation_total_time_ = graph_eval_end_time - graph_evaluation_start_time_;
|
||||
|
||||
if (!do_time_debug()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (name.empty()) {
|
||||
printf("Depsgraph updated in %f seconds.\n", graph_evaluation_total_time_);
|
||||
}
|
||||
else {
|
||||
printf("Depsgraph [%s] updated in %f seconds.\n", name.c_str(), graph_evaluation_total_time_);
|
||||
}
|
||||
}
|
||||
|
||||
double DepsgraphDebug::total_evaluation_time() const
|
||||
{
|
||||
return graph_evaluation_total_time_;
|
||||
}
|
||||
|
||||
bool terminal_do_color()
|
||||
{
|
||||
return (G.debug & G_DEBUG_DEPSGRAPH_PRETTY) != 0;
|
||||
}
|
||||
|
||||
std::string color_for_pointer(const void *pointer)
|
||||
{
|
||||
if (!terminal_do_color()) {
|
||||
return "";
|
||||
}
|
||||
int r, g, b;
|
||||
BLI_hash_pointer_to_color(pointer, &r, &g, &b);
|
||||
char buffer[64];
|
||||
SNPRINTF(buffer, TRUECOLOR_ANSI_COLOR_FORMAT, r, g, b);
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
std::string color_end()
|
||||
{
|
||||
if (!terminal_do_color()) {
|
||||
return "";
|
||||
}
|
||||
return std::string(TRUECOLOR_ANSI_COLOR_FINISH);
|
||||
}
|
||||
|
||||
} // namespace blender::deg
|
||||
@@ -0,0 +1,72 @@
|
||||
/* SPDX-FileCopyrightText: 2013 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup depsgraph
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "BKE_global.hh" // IWYU pragma: keep
|
||||
|
||||
namespace blender::deg {
|
||||
|
||||
class DepsgraphDebug {
|
||||
public:
|
||||
DepsgraphDebug();
|
||||
|
||||
bool do_time_debug() const;
|
||||
|
||||
void begin_graph_evaluation();
|
||||
void end_graph_evaluation();
|
||||
|
||||
double total_evaluation_time() const;
|
||||
|
||||
/* NOTE: Corresponds to G_DEBUG_DEPSGRAPH_* flags. */
|
||||
int flags;
|
||||
|
||||
/* Name of this dependency graph (is used for debug prints, helping to distinguish graphs
|
||||
* created for different view layer). */
|
||||
std::string name;
|
||||
|
||||
protected:
|
||||
/* Maximum number of counters used to calculate frame rate of depsgraph update. */
|
||||
static const constexpr int MAX_FPS_COUNTERS = 64;
|
||||
|
||||
/* Point in time when last graph evaluation began.
|
||||
* Is initialized from begin_graph_evaluation().
|
||||
*/
|
||||
double graph_evaluation_start_time_;
|
||||
/* Total time of the last evaluation. */
|
||||
double graph_evaluation_total_time_;
|
||||
};
|
||||
|
||||
#define DEG_DEBUG_PRINTF(depsgraph, type, ...) \
|
||||
do { \
|
||||
if (DEG_debug_flags_get(depsgraph) & G_DEBUG_DEPSGRAPH_##type) { \
|
||||
DEG_debug_print_begin(depsgraph); \
|
||||
fprintf(stdout, __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define DEG_GLOBAL_DEBUG_PRINTF(type, ...) \
|
||||
do { \
|
||||
if (G.debug & G_DEBUG_DEPSGRAPH_##type) { \
|
||||
fprintf(stdout, __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define DEG_ERROR_PRINTF(...) \
|
||||
do { \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
fflush(stderr); \
|
||||
} while (0)
|
||||
|
||||
bool terminal_do_color();
|
||||
std::string color_for_pointer(const void *pointer);
|
||||
std::string color_end();
|
||||
|
||||
} // namespace blender::deg
|
||||
@@ -0,0 +1,529 @@
|
||||
/* SPDX-FileCopyrightText: 2014 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup depsgraph
|
||||
*
|
||||
* Implementation of tools for debugging the depsgraph
|
||||
*/
|
||||
|
||||
#include <cstdarg>
|
||||
|
||||
#include "BLI_dot_export.hh"
|
||||
|
||||
#include "DEG_depsgraph.hh"
|
||||
#include "DEG_depsgraph_debug.hh"
|
||||
|
||||
#include "intern/depsgraph.hh"
|
||||
#include "intern/depsgraph_relation.hh"
|
||||
|
||||
#include "intern/node/deg_node_component.hh"
|
||||
#include "intern/node/deg_node_id.hh"
|
||||
#include "intern/node/deg_node_operation.hh"
|
||||
#include "intern/node/deg_node_time.hh"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace blender {
|
||||
|
||||
/* ****************** */
|
||||
/* Graphviz Debugging */
|
||||
|
||||
namespace deg {
|
||||
|
||||
/* Only one should be enabled, defines whether graphviz nodes
|
||||
* get colored by individual types or classes.
|
||||
*/
|
||||
#define COLOR_SCHEME_NODE_CLASS 1
|
||||
// #define COLOR_SCHEME_NODE_TYPE 2
|
||||
|
||||
static const char *deg_debug_graphviz_fontname = "helvetica";
|
||||
static float deg_debug_graphviz_graph_label_size = 20.0f;
|
||||
static float deg_debug_graphviz_node_label_size = 14.0f;
|
||||
static const int deg_debug_max_colors = 12;
|
||||
#ifdef COLOR_SCHEME_NODE_TYPE
|
||||
static const char *deg_debug_colors[] = {
|
||||
"#a6cee3",
|
||||
"#1f78b4",
|
||||
"#b2df8a",
|
||||
"#33a02c",
|
||||
"#fb9a99",
|
||||
"#e31a1c",
|
||||
"#fdbf6f",
|
||||
"#ff7f00",
|
||||
"#cab2d6",
|
||||
"#6a3d9a",
|
||||
"#ffff99",
|
||||
"#b15928",
|
||||
"#ff00ff",
|
||||
};
|
||||
#endif
|
||||
static const char *deg_debug_colors_light[] = {
|
||||
"#8dd3c7",
|
||||
"#ffffb3",
|
||||
"#bebada",
|
||||
"#fb8072",
|
||||
"#80b1d3",
|
||||
"#fdb462",
|
||||
"#b3de69",
|
||||
"#fccde5",
|
||||
"#d9d9d9",
|
||||
"#bc80bd",
|
||||
"#ccebc5",
|
||||
"#ffed6f",
|
||||
"#ff00ff",
|
||||
};
|
||||
|
||||
#ifdef COLOR_SCHEME_NODE_TYPE
|
||||
static const int deg_debug_node_type_color_map[][2] = {
|
||||
{NodeType::TIMESOURCE, 0},
|
||||
{NodeType::ID_REF, 1},
|
||||
|
||||
/* Outer Types */
|
||||
{NodeType::PARAMETERS, 2},
|
||||
{NodeType::ANIMATION, 4},
|
||||
{NodeType::TRANSFORM, 5},
|
||||
{NodeType::GEOMETRY, 6},
|
||||
{NodeType::SEQUENCER, 7},
|
||||
{NodeType::SHADING, 8},
|
||||
{NodeType::CACHE, 9},
|
||||
{NodeType::POINT_CACHE, 10},
|
||||
{NodeType::LAYER_COLLECTIONS, 11},
|
||||
{NodeType::COPY_ON_EVAL, 12},
|
||||
{-1, 0},
|
||||
};
|
||||
#endif
|
||||
|
||||
static int deg_debug_node_color_index(const Node *node)
|
||||
{
|
||||
#ifdef COLOR_SCHEME_NODE_CLASS
|
||||
/* Some special types. */
|
||||
switch (node->type) {
|
||||
case NodeType::ID_REF:
|
||||
return 5;
|
||||
case NodeType::OPERATION: {
|
||||
OperationNode *op_node = static_cast<OperationNode *>(const_cast<Node *>(node));
|
||||
if (op_node->is_noop()) {
|
||||
if (op_node->flag & OperationFlag::DEPSOP_FLAG_PINNED) {
|
||||
return 7;
|
||||
}
|
||||
return 8;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* Do others based on class. */
|
||||
switch (node->get_class()) {
|
||||
case NodeClass::OPERATION:
|
||||
return 4;
|
||||
case NodeClass::COMPONENT:
|
||||
return 1;
|
||||
default:
|
||||
return 9;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef COLOR_SCHEME_NODE_TYPE
|
||||
const int (*pair)[2];
|
||||
for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; pair++) {
|
||||
if ((*pair)[0] == node->type) {
|
||||
return (*pair)[1];
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
struct DotExportContext {
|
||||
bool show_tags;
|
||||
dot_export::DirectedGraph &digraph;
|
||||
Map<const Node *, dot_export::Node *> nodes_map;
|
||||
Map<const Node *, dot_export::Cluster *> clusters_map;
|
||||
};
|
||||
|
||||
static void deg_debug_graphviz_legend_color(const char *name,
|
||||
const char *color,
|
||||
std::stringstream &ss)
|
||||
{
|
||||
|
||||
ss << "<TR>";
|
||||
ss << "<TD>" << name << "</TD>";
|
||||
ss << "<TD BGCOLOR=\"" << color << "\"></TD>";
|
||||
ss << "</TR>";
|
||||
}
|
||||
|
||||
static void deg_debug_graphviz_legend(DotExportContext &ctx)
|
||||
{
|
||||
dot_export::Node &legend_node = ctx.digraph.new_node("");
|
||||
legend_node.attributes.set("rank", "sink");
|
||||
legend_node.attributes.set("shape", "none");
|
||||
legend_node.attributes.set("margin", 0);
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "<";
|
||||
ss << R"(<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">)";
|
||||
ss << "<TR><TD COLSPAN=\"2\"><B>Legend</B></TD></TR>";
|
||||
|
||||
#ifdef COLOR_SCHEME_NODE_CLASS
|
||||
const char **colors = deg_debug_colors_light;
|
||||
deg_debug_graphviz_legend_color("Operation", colors[4], ss);
|
||||
deg_debug_graphviz_legend_color("Component", colors[1], ss);
|
||||
deg_debug_graphviz_legend_color("ID Node", colors[5], ss);
|
||||
deg_debug_graphviz_legend_color("NOOP", colors[8], ss);
|
||||
deg_debug_graphviz_legend_color("Pinned OP", colors[7], ss);
|
||||
#endif
|
||||
|
||||
#ifdef COLOR_SCHEME_NODE_TYPE
|
||||
const int (*pair)[2];
|
||||
for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; pair++) {
|
||||
DepsNodeFactory *nti = type_get_factory((NodeType)(*pair)[0]);
|
||||
deg_debug_graphviz_legend_color(
|
||||
ctx, nti->tname().c_str(), deg_debug_colors_light[(*pair)[1] % deg_debug_max_colors], ss);
|
||||
}
|
||||
#endif
|
||||
|
||||
ss << "</TABLE>";
|
||||
ss << ">";
|
||||
legend_node.attributes.set("label", ss.str());
|
||||
legend_node.attributes.set("fontname", deg_debug_graphviz_fontname);
|
||||
}
|
||||
|
||||
static void deg_debug_graphviz_node_color(DotExportContext &ctx,
|
||||
const Node *node,
|
||||
dot_export::Attributes &dot_attributes)
|
||||
{
|
||||
const char *color_default = "black";
|
||||
const char *color_modified = "orangered4";
|
||||
const char *color_update = "dodgerblue3";
|
||||
const char *color = color_default;
|
||||
if (ctx.show_tags) {
|
||||
if (node->get_class() == NodeClass::OPERATION) {
|
||||
OperationNode *op_node = static_cast<OperationNode *>(const_cast<Node *>(node));
|
||||
if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) {
|
||||
color = color_modified;
|
||||
}
|
||||
else if (op_node->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
|
||||
color = color_update;
|
||||
}
|
||||
}
|
||||
}
|
||||
dot_attributes.set("color", color);
|
||||
}
|
||||
|
||||
static void deg_debug_graphviz_node_penwidth(DotExportContext &ctx,
|
||||
const Node *node,
|
||||
dot_export::Attributes &dot_attributes)
|
||||
{
|
||||
float penwidth_default = 1.0f;
|
||||
float penwidth_modified = 4.0f;
|
||||
float penwidth_update = 4.0f;
|
||||
float penwidth = penwidth_default;
|
||||
if (ctx.show_tags) {
|
||||
if (node->get_class() == NodeClass::OPERATION) {
|
||||
OperationNode *op_node = static_cast<OperationNode *>(const_cast<Node *>(node));
|
||||
if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) {
|
||||
penwidth = penwidth_modified;
|
||||
}
|
||||
else if (op_node->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
|
||||
penwidth = penwidth_update;
|
||||
}
|
||||
}
|
||||
}
|
||||
dot_attributes.set("penwidth", penwidth);
|
||||
}
|
||||
|
||||
static void deg_debug_graphviz_node_fillcolor(const Node *node,
|
||||
dot_export::Attributes &dot_attributes)
|
||||
{
|
||||
const char *defaultcolor = "gainsboro";
|
||||
int color_index = deg_debug_node_color_index(node);
|
||||
const char *fillcolor = color_index < 0 ?
|
||||
defaultcolor :
|
||||
deg_debug_colors_light[color_index % deg_debug_max_colors];
|
||||
dot_attributes.set("fillcolor", fillcolor);
|
||||
}
|
||||
|
||||
static void deg_debug_graphviz_relation_color(const Relation *rel, dot_export::DirectedEdge &edge)
|
||||
{
|
||||
const char *color_default = "black";
|
||||
const char *color_cyclic = "red4"; /* The color of crime scene. */
|
||||
const char *color_godmode = "blue4"; /* The color of beautiful sky. */
|
||||
const char *color = color_default;
|
||||
if (rel->flag & RELATION_FLAG_CYCLIC) {
|
||||
color = color_cyclic;
|
||||
}
|
||||
else if (rel->flag & RELATION_FLAG_GODMODE) {
|
||||
color = color_godmode;
|
||||
}
|
||||
edge.attributes.set("color", color);
|
||||
}
|
||||
|
||||
static void deg_debug_graphviz_relation_style(const Relation *rel, dot_export::DirectedEdge &edge)
|
||||
{
|
||||
const char *style_default = "solid";
|
||||
const char *style_no_flush = "dashed";
|
||||
const char *style_flush_user_only = "dotted";
|
||||
const char *style = style_default;
|
||||
if (rel->flag & RELATION_FLAG_NO_FLUSH) {
|
||||
style = style_no_flush;
|
||||
}
|
||||
if (rel->flag & RELATION_FLAG_FLUSH_USER_EDIT_ONLY) {
|
||||
style = style_flush_user_only;
|
||||
}
|
||||
edge.attributes.set("style", style);
|
||||
}
|
||||
|
||||
static void deg_debug_graphviz_relation_arrowhead(const Relation *rel,
|
||||
dot_export::DirectedEdge &edge)
|
||||
{
|
||||
const char *shape_default = "normal";
|
||||
const char *shape_no_cow = "box";
|
||||
const char *shape = shape_default;
|
||||
if (rel->from->get_class() == NodeClass::OPERATION &&
|
||||
rel->to->get_class() == NodeClass::OPERATION)
|
||||
{
|
||||
OperationNode *op_from = static_cast<OperationNode *>(rel->from);
|
||||
OperationNode *op_to = static_cast<OperationNode *>(rel->to);
|
||||
if (op_from->owner->type == NodeType::COPY_ON_EVAL &&
|
||||
/* The #ID::recalc flag depends on run-time state which is not valid at this point in time.
|
||||
* Pass in all flags although there may be a better way to represent this. */
|
||||
!op_to->owner->need_tag_cow_before_update(ID_RECALC_ALL))
|
||||
{
|
||||
shape = shape_no_cow;
|
||||
}
|
||||
}
|
||||
edge.attributes.set("arrowhead", shape);
|
||||
}
|
||||
|
||||
static void deg_debug_graphviz_node_style(DotExportContext &ctx,
|
||||
const Node *node,
|
||||
dot_export::Attributes &dot_attributes)
|
||||
{
|
||||
StringRef base_style = "filled"; /* default style */
|
||||
if (ctx.show_tags) {
|
||||
if (node->get_class() == NodeClass::OPERATION) {
|
||||
OperationNode *op_node = static_cast<OperationNode *>(const_cast<Node *>(node));
|
||||
if (op_node->flag & (DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE)) {
|
||||
base_style = "striped";
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (node->get_class()) {
|
||||
case NodeClass::GENERIC:
|
||||
dot_attributes.set("style", base_style);
|
||||
break;
|
||||
case NodeClass::COMPONENT:
|
||||
dot_attributes.set("style", base_style);
|
||||
break;
|
||||
case NodeClass::OPERATION:
|
||||
dot_attributes.set("style", base_style + ",rounded");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void deg_debug_graphviz_node_single(DotExportContext &ctx,
|
||||
const Node *node,
|
||||
dot_export::Cluster *parent_cluster)
|
||||
{
|
||||
std::string name = node->identifier();
|
||||
|
||||
dot_export::Node &dot_node = ctx.digraph.new_node(name);
|
||||
ctx.nodes_map.add_new(node, &dot_node);
|
||||
dot_node.set_parent_cluster(parent_cluster);
|
||||
dot_node.attributes.set("fontname", deg_debug_graphviz_fontname);
|
||||
dot_node.attributes.set("frontsize", deg_debug_graphviz_node_label_size);
|
||||
dot_node.attributes.set("shape", "box");
|
||||
|
||||
deg_debug_graphviz_node_style(ctx, node, dot_node.attributes);
|
||||
deg_debug_graphviz_node_color(ctx, node, dot_node.attributes);
|
||||
deg_debug_graphviz_node_fillcolor(node, dot_node.attributes);
|
||||
deg_debug_graphviz_node_penwidth(ctx, node, dot_node.attributes);
|
||||
}
|
||||
|
||||
static dot_export::Cluster °_debug_graphviz_node_cluster_create(
|
||||
DotExportContext &ctx, const Node *node, dot_export::Cluster *parent_cluster)
|
||||
{
|
||||
std::string name = node->identifier();
|
||||
dot_export::Cluster &cluster = ctx.digraph.new_cluster(name);
|
||||
cluster.set_parent_cluster(parent_cluster);
|
||||
cluster.attributes.set("fontname", deg_debug_graphviz_fontname);
|
||||
cluster.attributes.set("fontsize", deg_debug_graphviz_node_label_size);
|
||||
cluster.attributes.set("margin", 16);
|
||||
deg_debug_graphviz_node_style(ctx, node, cluster.attributes);
|
||||
deg_debug_graphviz_node_color(ctx, node, cluster.attributes);
|
||||
deg_debug_graphviz_node_fillcolor(node, cluster.attributes);
|
||||
deg_debug_graphviz_node_penwidth(ctx, node, cluster.attributes);
|
||||
/* dummy node, so we can add edges between clusters */
|
||||
dot_export::Node &dot_node = ctx.digraph.new_node("");
|
||||
dot_node.attributes.set("shape", "point");
|
||||
dot_node.attributes.set("style", "invis");
|
||||
dot_node.set_parent_cluster(&cluster);
|
||||
ctx.nodes_map.add_new(node, &dot_node);
|
||||
ctx.clusters_map.add_new(node, &cluster);
|
||||
return cluster;
|
||||
}
|
||||
|
||||
static void deg_debug_graphviz_graph_nodes(DotExportContext &ctx, const Depsgraph *graph);
|
||||
static void deg_debug_graphviz_graph_relations(DotExportContext &ctx, const Depsgraph *graph);
|
||||
|
||||
static void deg_debug_graphviz_node(DotExportContext &ctx,
|
||||
const Node *node,
|
||||
dot_export::Cluster *parent_cluster)
|
||||
{
|
||||
switch (node->type) {
|
||||
case NodeType::ID_REF: {
|
||||
const IDNode *id_node = static_cast<const IDNode *>(node);
|
||||
if (id_node->components.is_empty()) {
|
||||
deg_debug_graphviz_node_single(ctx, node, parent_cluster);
|
||||
}
|
||||
else {
|
||||
dot_export::Cluster &cluster = deg_debug_graphviz_node_cluster_create(
|
||||
ctx, node, parent_cluster);
|
||||
for (const ComponentNode *comp : id_node->components.values()) {
|
||||
deg_debug_graphviz_node(ctx, comp, &cluster);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NodeType::PARAMETERS:
|
||||
case NodeType::ANIMATION:
|
||||
case NodeType::TRANSFORM:
|
||||
case NodeType::GEOMETRY:
|
||||
case NodeType::SEQUENCER:
|
||||
case NodeType::COMPOSITOR:
|
||||
case NodeType::EVAL_POSE:
|
||||
case NodeType::BONE:
|
||||
case NodeType::SHADING:
|
||||
case NodeType::CACHE:
|
||||
case NodeType::POINT_CACHE:
|
||||
case NodeType::IMAGE_ANIMATION:
|
||||
case NodeType::LAYER_COLLECTIONS:
|
||||
case NodeType::PARTICLE_SYSTEM:
|
||||
case NodeType::PARTICLE_SETTINGS:
|
||||
case NodeType::COPY_ON_EVAL:
|
||||
case NodeType::OBJECT_FROM_LAYER:
|
||||
case NodeType::HIERARCHY:
|
||||
case NodeType::BATCH_CACHE:
|
||||
case NodeType::INSTANCING:
|
||||
case NodeType::SYNCHRONIZATION:
|
||||
case NodeType::AUDIO:
|
||||
case NodeType::ARMATURE:
|
||||
case NodeType::GENERIC_DATABLOCK:
|
||||
case NodeType::SCENE:
|
||||
case NodeType::VISIBILITY:
|
||||
case NodeType::NTREE_OUTPUT:
|
||||
case NodeType::NTREE_GEOMETRY_PREPROCESS: {
|
||||
ComponentNode *comp_node = static_cast<ComponentNode *>(const_cast<Node *>(node));
|
||||
if (comp_node->operations.is_empty()) {
|
||||
deg_debug_graphviz_node_single(ctx, node, parent_cluster);
|
||||
}
|
||||
else {
|
||||
dot_export::Cluster &cluster = deg_debug_graphviz_node_cluster_create(
|
||||
ctx, node, parent_cluster);
|
||||
for (Node *op_node : comp_node->operations) {
|
||||
deg_debug_graphviz_node(ctx, op_node, &cluster);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NodeType::UNDEFINED:
|
||||
case NodeType::TIMESOURCE:
|
||||
case NodeType::OPERATION:
|
||||
deg_debug_graphviz_node_single(ctx, node, parent_cluster);
|
||||
break;
|
||||
case NodeType::NUM_TYPES:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void deg_debug_graphviz_node_relations(DotExportContext &ctx, const Node *node)
|
||||
{
|
||||
for (Relation *rel : node->inlinks) {
|
||||
float penwidth = 2.0f;
|
||||
|
||||
const Node *head = rel->to; /* same as node */
|
||||
const Node *tail = rel->from;
|
||||
dot_export::Node &dot_tail = *ctx.nodes_map.lookup(tail);
|
||||
dot_export::Node &dot_head = *ctx.nodes_map.lookup(head);
|
||||
|
||||
dot_export::DirectedEdge &edge = ctx.digraph.new_edge(dot_tail, dot_head);
|
||||
|
||||
/* NOTE: without label an id seem necessary to avoid bugs in graphviz/dot. */
|
||||
edge.attributes.set("id", rel->name);
|
||||
deg_debug_graphviz_relation_color(rel, edge);
|
||||
deg_debug_graphviz_relation_style(rel, edge);
|
||||
deg_debug_graphviz_relation_arrowhead(rel, edge);
|
||||
edge.attributes.set("penwidth", penwidth);
|
||||
|
||||
/* NOTE: edge from node to our own cluster is not possible and gives graphviz
|
||||
* warning, avoid this here by just linking directly to the invisible
|
||||
* placeholder node. */
|
||||
dot_export::Cluster *tail_cluster = ctx.clusters_map.lookup_default(tail, nullptr);
|
||||
if (tail_cluster != nullptr && tail_cluster->contains(dot_head)) {
|
||||
edge.attributes.set("ltail", tail_cluster->name());
|
||||
}
|
||||
dot_export::Cluster *head_cluster = ctx.clusters_map.lookup_default(head, nullptr);
|
||||
if (head_cluster != nullptr && head_cluster->contains(dot_tail)) {
|
||||
edge.attributes.set("lhead", head_cluster->name());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void deg_debug_graphviz_graph_nodes(DotExportContext &ctx, const Depsgraph *graph)
|
||||
{
|
||||
for (Node *node : graph->id_nodes) {
|
||||
deg_debug_graphviz_node(ctx, node, nullptr);
|
||||
}
|
||||
TimeSourceNode *time_source = graph->find_time_source();
|
||||
if (time_source != nullptr) {
|
||||
deg_debug_graphviz_node(ctx, time_source, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
static void deg_debug_graphviz_graph_relations(DotExportContext &ctx, const Depsgraph *graph)
|
||||
{
|
||||
for (IDNode *id_node : graph->id_nodes) {
|
||||
for (ComponentNode *comp_node : id_node->components.values()) {
|
||||
for (OperationNode *op_node : comp_node->operations) {
|
||||
deg_debug_graphviz_node_relations(ctx, op_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TimeSourceNode *time_source = graph->find_time_source();
|
||||
if (time_source != nullptr) {
|
||||
deg_debug_graphviz_node_relations(ctx, time_source);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace deg
|
||||
|
||||
std::string DEG_debug_graph_to_dot(const Depsgraph &graph, const StringRef label)
|
||||
{
|
||||
const deg::Depsgraph °_graph = reinterpret_cast<const deg::Depsgraph &>(graph);
|
||||
|
||||
dot_export::DirectedGraph digraph;
|
||||
deg::DotExportContext ctx{false, digraph};
|
||||
|
||||
digraph.set_rankdir(dot_export::Attr_rankdir::LeftToRight);
|
||||
digraph.attributes.set("compound", "true");
|
||||
digraph.attributes.set("labelloc", "t");
|
||||
digraph.attributes.set("fontsize", deg::deg_debug_graphviz_graph_label_size);
|
||||
digraph.attributes.set("fontname", deg::deg_debug_graphviz_fontname);
|
||||
digraph.attributes.set("label", label);
|
||||
digraph.attributes.set("splines", "ortho");
|
||||
digraph.attributes.set("overlap", "scalexy");
|
||||
|
||||
deg::deg_debug_graphviz_graph_nodes(ctx, °_graph);
|
||||
deg::deg_debug_graphviz_graph_relations(ctx, °_graph);
|
||||
|
||||
deg::deg_debug_graphviz_legend(ctx);
|
||||
|
||||
return digraph.to_dot_string();
|
||||
}
|
||||
|
||||
} // namespace blender
|
||||
@@ -0,0 +1,154 @@
|
||||
/* SPDX-FileCopyrightText: 2017 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup depsgraph
|
||||
*/
|
||||
|
||||
#include "DEG_depsgraph_debug.hh"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdarg>
|
||||
|
||||
#include "BLI_compiler_attrs.h"
|
||||
#include "BLI_math_base.h"
|
||||
|
||||
#include "intern/depsgraph.hh"
|
||||
#include "intern/node/deg_node_id.hh"
|
||||
|
||||
#include "DNA_ID.h"
|
||||
|
||||
namespace blender {
|
||||
|
||||
#define NL "\r\n"
|
||||
|
||||
namespace deg {
|
||||
namespace {
|
||||
|
||||
struct DebugContext {
|
||||
FILE *file;
|
||||
const Depsgraph *graph;
|
||||
const char *label;
|
||||
const char *output_filename;
|
||||
};
|
||||
|
||||
struct StatsEntry {
|
||||
const IDNode *id_node;
|
||||
double time;
|
||||
};
|
||||
|
||||
/* TODO(sergey): De-duplicate with graphviz relation debugger. */
|
||||
void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...) ATTR_PRINTF_FORMAT(2, 3);
|
||||
void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vfprintf(ctx.file, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
inline double get_node_time(const DebugContext & /*ctx*/, const Node *node)
|
||||
{
|
||||
/* TODO(sergey): Figure out a nice way to define which exact time
|
||||
* we want to show. */
|
||||
return node->stats.current_time;
|
||||
}
|
||||
|
||||
bool stat_entry_comparator(const StatsEntry &a, const StatsEntry &b)
|
||||
{
|
||||
return a.time > b.time;
|
||||
}
|
||||
|
||||
std::string gnuplotify_id_code(const std::string &name)
|
||||
{
|
||||
return std::string("") + name[0] + name[1];
|
||||
}
|
||||
|
||||
std::string gnuplotify_name(const std::string &name)
|
||||
{
|
||||
std::string result;
|
||||
const int length = name.length();
|
||||
for (int i = 0; i < length; i++) {
|
||||
const char ch = name[i];
|
||||
if (ch == '_') {
|
||||
result += R"(\\\)";
|
||||
}
|
||||
result += ch;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void write_stats_data(const DebugContext &ctx)
|
||||
{
|
||||
/* Fill in array of all stats which are to be displayed. */
|
||||
Vector<StatsEntry> stats;
|
||||
stats.reserve(ctx.graph->id_nodes.size());
|
||||
for (const IDNode *id_node : ctx.graph->id_nodes) {
|
||||
const double time = get_node_time(ctx, id_node);
|
||||
if (time == 0.0) {
|
||||
continue;
|
||||
}
|
||||
StatsEntry entry;
|
||||
entry.id_node = id_node;
|
||||
entry.time = time;
|
||||
stats.append(entry);
|
||||
}
|
||||
/* Sort the data. */
|
||||
std::ranges::sort(stats, stat_entry_comparator);
|
||||
/* We limit number of entries, otherwise things become unreadable. */
|
||||
stats.resize(min_ii(stats.size(), 32));
|
||||
std::reverse(stats.begin(), stats.end());
|
||||
/* Print data to the file stream. */
|
||||
deg_debug_fprintf(ctx, "$data << EOD" NL);
|
||||
for (const StatsEntry &entry : stats) {
|
||||
deg_debug_fprintf(ctx,
|
||||
"\"[%s] %s\",%f" NL,
|
||||
gnuplotify_id_code(entry.id_node->id_orig->name).c_str(),
|
||||
gnuplotify_name(entry.id_node->id_orig->name + 2).c_str(),
|
||||
entry.time);
|
||||
}
|
||||
deg_debug_fprintf(ctx, "EOD" NL);
|
||||
}
|
||||
|
||||
void deg_debug_stats_gnuplot(const DebugContext &ctx)
|
||||
{
|
||||
/* Data itself. */
|
||||
write_stats_data(ctx);
|
||||
/* Optional label. */
|
||||
if (ctx.label && ctx.label[0]) {
|
||||
deg_debug_fprintf(ctx, "set title \"%s\"" NL, ctx.label);
|
||||
}
|
||||
/* Rest of the commands.
|
||||
* TODO(sergey): Need to decide on the resolution somehow. */
|
||||
deg_debug_fprintf(ctx, "set terminal pngcairo size 1920,1080" NL);
|
||||
deg_debug_fprintf(ctx, "set output \"%s\"" NL, ctx.output_filename);
|
||||
deg_debug_fprintf(ctx, "set grid" NL);
|
||||
deg_debug_fprintf(ctx, "set datafile separator ','" NL);
|
||||
deg_debug_fprintf(ctx, "set style fill solid" NL);
|
||||
deg_debug_fprintf(ctx,
|
||||
"plot \"$data\" using "
|
||||
"($2*0.5):0:($2*0.5):(0.2):yticlabels(1) "
|
||||
"with boxxyerrorbars t '' lt rgb \"#406090\"" NL);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace deg
|
||||
|
||||
void DEG_debug_stats_gnuplot(const Depsgraph *depsgraph,
|
||||
FILE *fp,
|
||||
const char *label,
|
||||
const char *output_filename)
|
||||
{
|
||||
if (depsgraph == nullptr) {
|
||||
return;
|
||||
}
|
||||
deg::DebugContext ctx;
|
||||
ctx.file = fp;
|
||||
ctx.graph = reinterpret_cast<deg::Depsgraph *>(const_cast<Depsgraph *>(depsgraph));
|
||||
ctx.label = label;
|
||||
ctx.output_filename = output_filename;
|
||||
deg::deg_debug_stats_gnuplot(ctx);
|
||||
}
|
||||
|
||||
} // namespace blender
|
||||
Reference in New Issue
Block a user