Geometry Nodes: don't log full fields when not necessary

Previously, the field on every socket was logged for later use. This had
two main negative consequences:
* Increased memory usage, because the fields may contain a lot of data
  under some circumstances (e.g. a Ray Cast field contains the target geometry).
* Decreased performance, because anonymous attributes could not be
  removed from geometry automatically, because there were still fields that
  referenced them.

Now most fields are not logged anymore. Only those that are viewed by a
spreadsheet and constant fields. The required inputs of a field are still
logged in string form to keep socket inspection working.
This commit is contained in:
Jacques Lucke 2021-10-26 12:48:29 +02:00
parent 41a4c62c31
commit d20fa6c4d4
4 changed files with 141 additions and 61 deletions

View File

@ -854,60 +854,7 @@ static void create_inspection_string_for_generic_value(const geo_log::GenericVal
const GPointer value = value_log.value();
const CPPType &type = *value.type();
if (const FieldCPPType *field_type = dynamic_cast<const FieldCPPType *>(&type)) {
const CPPType &base_type = field_type->field_type();
BUFFER_FOR_CPP_TYPE_VALUE(base_type, buffer);
const GField &field = field_type->get_gfield(value.get());
if (field.node().depends_on_input()) {
if (base_type.is<int>()) {
ss << TIP_("Integer Field");
}
else if (base_type.is<float>()) {
ss << TIP_("Float Field");
}
else if (base_type.is<blender::float3>()) {
ss << TIP_("Vector Field");
}
else if (base_type.is<bool>()) {
ss << TIP_("Boolean Field");
}
else if (base_type.is<std::string>()) {
ss << TIP_("String Field");
}
ss << TIP_(" based on:\n");
/* Use vector set to deduplicate inputs. */
VectorSet<std::reference_wrapper<const FieldInput>> field_inputs;
field.node().foreach_field_input(
[&](const FieldInput &field_input) { field_inputs.add(field_input); });
for (const FieldInput &field_input : field_inputs) {
ss << "\u2022 " << field_input.socket_inspection_name();
if (field_input != field_inputs.as_span().last().get()) {
ss << ".\n";
}
}
}
else {
blender::fn::evaluate_constant_field(field, buffer);
if (base_type.is<int>()) {
ss << *(int *)buffer << TIP_(" (Integer)");
}
else if (base_type.is<float>()) {
ss << *(float *)buffer << TIP_(" (Float)");
}
else if (base_type.is<blender::float3>()) {
ss << *(blender::float3 *)buffer << TIP_(" (Vector)");
}
else if (base_type.is<bool>()) {
ss << ((*(bool *)buffer) ? TIP_("True") : TIP_("False")) << TIP_(" (Boolean)");
}
else if (base_type.is<std::string>()) {
ss << *(std::string *)buffer << TIP_(" (String)");
}
base_type.destruct(buffer);
}
}
else if (type.is<Object *>()) {
if (type.is<Object *>()) {
id_to_inspection_string((ID *)*value.get<Object *>(), ID_OB);
}
else if (type.is<Material *>()) {
@ -924,6 +871,71 @@ static void create_inspection_string_for_generic_value(const geo_log::GenericVal
}
}
static void create_inspection_string_for_gfield(const geo_log::GFieldValueLog &value_log,
std::stringstream &ss)
{
const CPPType &type = value_log.type();
const GField &field = value_log.field();
const Span<std::string> input_tooltips = value_log.input_tooltips();
if (input_tooltips.is_empty()) {
if (field) {
BUFFER_FOR_CPP_TYPE_VALUE(type, buffer);
blender::fn::evaluate_constant_field(field, buffer);
if (type.is<int>()) {
ss << *(int *)buffer << TIP_(" (Integer)");
}
else if (type.is<float>()) {
ss << *(float *)buffer << TIP_(" (Float)");
}
else if (type.is<blender::float3>()) {
ss << *(blender::float3 *)buffer << TIP_(" (Vector)");
}
else if (type.is<bool>()) {
ss << ((*(bool *)buffer) ? TIP_("True") : TIP_("False")) << TIP_(" (Boolean)");
}
else if (type.is<std::string>()) {
ss << *(std::string *)buffer << TIP_(" (String)");
}
type.destruct(buffer);
}
else {
/* Constant values should always be logged. */
BLI_assert_unreachable();
ss << "Value has not been logged";
}
}
else {
if (type.is<int>()) {
ss << TIP_("Integer Field");
}
else if (type.is<float>()) {
ss << TIP_("Float Field");
}
else if (type.is<blender::float3>()) {
ss << TIP_("Vector Field");
}
else if (type.is<bool>()) {
ss << TIP_("Boolean Field");
}
else if (type.is<std::string>()) {
ss << TIP_("String Field");
}
else if (type.is<blender::ColorGeometry4f>()) {
ss << TIP_("Color Field");
}
ss << TIP_(" based on:\n");
for (const int i : input_tooltips.index_range()) {
const blender::StringRef tooltip = input_tooltips[i];
ss << "\u2022 " << tooltip;
if (i < input_tooltips.size() - 1) {
ss << ".\n";
}
}
}
}
static void create_inspection_string_for_geometry(const geo_log::GeometryValueLog &value_log,
std::stringstream &ss)
{
@ -1015,6 +1027,10 @@ static std::optional<std::string> create_socket_inspection_string(bContext *C,
dynamic_cast<const geo_log::GenericValueLog *>(value_log)) {
create_inspection_string_for_generic_value(*generic_value_log, ss);
}
if (const geo_log::GFieldValueLog *gfield_value_log =
dynamic_cast<const geo_log::GFieldValueLog *>(value_log)) {
create_inspection_string_for_gfield(*gfield_value_log, ss);
}
else if (const geo_log::GeometryValueLog *geo_value_log =
dynamic_cast<const geo_log::GeometryValueLog *>(value_log)) {
create_inspection_string_for_geometry(*geo_value_log, ss);

View File

@ -574,14 +574,12 @@ static void find_fields_to_evaluate(const SpaceSpreadsheet *sspreadsheet,
if (value_log == nullptr) {
continue;
}
if (const geo_log::GenericValueLog *generic_value_log =
dynamic_cast<const geo_log::GenericValueLog *>(value_log)) {
const fn::GPointer value = generic_value_log->value();
if (!dynamic_cast<const fn::FieldCPPType *>(value.type())) {
continue;
if (const geo_log::GFieldValueLog *field_value_log =
dynamic_cast<const geo_log::GFieldValueLog *>(value_log)) {
const GField &field = field_value_log->field();
if (field) {
r_fields.add("Viewer", std::move(field));
}
GField field = *(const GField *)value.get();
r_fields.add("Viewer", std::move(field));
}
}
}

View File

@ -76,6 +76,31 @@ class GenericValueLog : public ValueLog {
}
};
class GFieldValueLog : public ValueLog {
private:
fn::GField field_;
const fn::CPPType &type_;
Vector<std::string> input_tooltips_;
public:
GFieldValueLog(fn::GField field, bool log_full_field);
const fn::GField &field() const
{
return field_;
}
Span<std::string> input_tooltips() const
{
return input_tooltips_;
}
const fn::CPPType &type() const
{
return type_;
}
};
struct GeometryAttributeInfo {
std::string name;
AttributeDomain domain;

View File

@ -21,9 +21,16 @@
#include "DNA_modifier_types.h"
#include "DNA_space_types.h"
#include "FN_field_cpp_type.hh"
#include "BLT_translation.h"
namespace blender::nodes::geometry_nodes_eval_log {
using fn::CPPType;
using fn::FieldCPPType;
using fn::FieldInput;
using fn::GField;
ModifierLog::ModifierLog(GeoLogger &logger)
: input_geometry_log_(std::move(logger.input_geometry_log_)),
@ -168,6 +175,20 @@ const SocketLog *NodeLog::lookup_socket_log(const bNode &node, const bNodeSocket
return this->lookup_socket_log((eNodeSocketInOut)socket.in_out, index);
}
GFieldValueLog::GFieldValueLog(fn::GField field, bool log_full_field) : type_(field.cpp_type())
{
VectorSet<std::reference_wrapper<const FieldInput>> field_inputs;
field.node().foreach_field_input(
[&](const FieldInput &field_input) { field_inputs.add(field_input); });
for (const FieldInput &field_input : field_inputs) {
input_tooltips_.append(field_input.socket_inspection_name());
}
if (log_full_field) {
field_ = std::move(field);
}
}
GeometryValueLog::GeometryValueLog(const GeometrySet &geometry_set, bool log_full_geometry)
{
static std::array all_component_types = {GEO_COMPONENT_TYPE_CURVE,
@ -382,6 +403,26 @@ void LocalGeoLogger::log_value_for_sockets(Span<DSocket> sockets, GPointer value
geometry_set, log_full_geometry);
values_.append({copied_sockets, std::move(value_log)});
}
else if (const FieldCPPType *field_type = dynamic_cast<const FieldCPPType *>(&type)) {
GField field = field_type->get_gfield(value.get());
bool log_full_field = false;
if (!field.node().depends_on_input()) {
/* Always log constant fields so that their value can be shown in socket inspection.
* In the future we can also evaluate the field here and only store the value. */
log_full_field = true;
}
if (!log_full_field) {
for (const DSocket &socket : sockets) {
if (main_logger_->log_full_sockets_.contains(socket)) {
log_full_field = true;
break;
}
}
}
destruct_ptr<GFieldValueLog> value_log = allocator_->construct<GFieldValueLog>(
std::move(field), log_full_field);
values_.append({copied_sockets, std::move(value_log)});
}
else {
void *buffer = allocator_->allocate(type.size(), type.alignment());
type.copy_construct(value.get(), buffer);