Commit: 70eaba3cb1d74d5fb9ae12a7997ba1e8c5622a9a Author: Hans Goudey Date: Wed Aug 25 16:23:46 2021 -0500 Branches: temp-geometry-nodes-fields--fields https://developer.blender.org/rB70eaba3cb1d74d5fb9ae12a7997ba1e8c5622a9a
Basic constant input test passes =================================================================== M source/blender/functions/CMakeLists.txt M source/blender/functions/FN_field.hh A source/blender/functions/intern/field.cc M source/blender/functions/tests/FN_field_test.cc =================================================================== diff --git a/source/blender/functions/CMakeLists.txt b/source/blender/functions/CMakeLists.txt index a4ba9a61a85..5941034de78 100644 --- a/source/blender/functions/CMakeLists.txt +++ b/source/blender/functions/CMakeLists.txt @@ -28,6 +28,7 @@ set(INC_SYS set(SRC intern/cpp_types.cc + intern/field.cc intern/generic_vector_array.cc intern/generic_virtual_array.cc intern/generic_virtual_vector_array.cc diff --git a/source/blender/functions/FN_field.hh b/source/blender/functions/FN_field.hh index 208f3ce2d76..daff025d0d6 100644 --- a/source/blender/functions/FN_field.hh +++ b/source/blender/functions/FN_field.hh @@ -24,7 +24,6 @@ #include "BLI_map.hh" #include "BLI_vector.hh" -#include "FN_generic_array.hh" #include "FN_generic_virtual_array.hh" #include "FN_multi_function_procedure.hh" #include "FN_multi_function_procedure_builder.hh" @@ -33,152 +32,103 @@ namespace blender::fn { class Field; +using FieldPtr = std::unique_ptr<Field>; class Field { - fn::CPPType *type_; + const fn::CPPType *type_; + std::string debug_name_ = ""; public: - fn::CPPType &type() + virtual ~Field() = default; + Field(const fn::CPPType &type, std::string &&debug_name = "") + : type_(&type), debug_name_(std::move(debug_name)) { + } + + const fn::CPPType &type() const + { + BLI_assert(type_ != nullptr); return *type_; } - virtual void foreach_input_recursive(blender::FunctionRef<void(const InputField &input)> fn) = 0; - virtual void foreach_input(blender::FunctionRef<void(const InputField &input)> fn) = 0; + blender::StringRef debug_name() const + { + return debug_name_; + } + + virtual void foreach_input(blender::FunctionRef<void(const Field &input)> UNUSED(fn)) const = 0; + virtual void foreach_input_recursive( + blender::FunctionRef<void(const Field &input)> UNUSED(fn)) const = 0; }; +/** + * A field that doesn't have any dependencies on other fields. + * + * TODO: It might be an elegant simplification if every single field was a multi-function field, + * and input fields just happened to have no inputs. Then it might not need to be a virtual class, + * since the dynamic behavior would be contained in the multifunction, which would be very nice. + */ class InputField : public Field { - public: - virtual GVArrayPtr get_data(IndexMask mask) const = 0; - void foreach_input_recursive(blender::FunctionRef<void(const InputField &input)> fn) final + InputField(const CPPType &type) : Field(type) { } - void foreach_input(blender::FunctionRef<void(const InputField &input)> fn) final + + void foreach_input(blender::FunctionRef<void(const Field &input)> UNUSED(fn)) const final { } -}; - -class MultiFunctionField final : public Field { - blender::Vector<std::shared_ptr<Field>> input_fields_; - MultiFunction &function_; - - public: - void foreach_input_recursive(blender::FunctionRef<void(const InputField &input)> fn) final + void foreach_input_recursive( + blender::FunctionRef<void(const Field &input)> UNUSED(fn)) const final { - for (const std::shared_ptr<Field> &field : input_fields_) { - if (const InputField *input_field = dynamic_cast<const InputField *>(field.get())) { - fn(*input_field); - } - else { - field->foreach_input(fn); - } - } } - void foreach_input(blender::FunctionRef<void(const InputField &input)> fn) final + virtual GVArrayPtr get_data(IndexMask mask) const = 0; + + /** + * Return true when the field input is the same as another field, used as an + * optimization to avoid creating multiple virtual arrays for the same input node. + */ + virtual bool equals(const InputField &UNUSED(other)) { - for (const std::shared_ptr<Field> &field : input_fields_) { - if (const InputField *input_field = dynamic_cast<const InputField *>(field.get())) { - fn(*input_field); - } - } + return false; } }; -void add_procedure_inputs_recursive(const Field &field, MFProcedureBuilder &builder) -{ - field.foreach_input() -} - /** - * Evaluate more than one prodecure at a time + * A field that takes inputs */ -void evaluate_fields(const Span<std::shared_ptr<Field>> fields, - const MutableSpan<GMutableSpan> outputs, - const IndexMask mask) -{ - blender::Map<const InputField *, GVArrayPtr> computed_inputs; - for (const std::shared_ptr<Field> &field : fields) { - field->foreach_input_recursive([&](const InputField &input_field) { - if (!computed_inputs.contains(&input_field)) { - computed_inputs.add_new(&input_field, input_field.get_data(mask)); - } - }); - } - - /* Build procedure. */ - MFProcedure procedure; - MFProcedureBuilder builder{procedure}; - - Map<const Field *, MFVariable *> fields_to_variables; - Map<const GMutableSpan, MFVariable *> outputs_to_variables; - - /* Add the unique inputs. */ - for (blender::Map<const InputField *, GVArrayPtr>::Item item : computed_inputs.items()) { - fields_to_variables.add_new( - item.key, &builder.add_parameter(MFParamType::ForSingleInput(item.value->type()))); - } +class MultiFunctionField final : public Field { + blender::Vector<FieldPtr> input_fields_; + const MultiFunction *function_; - /* Add the inputs recursively for the entire group of nodes. */ - builder.add_return(); - for (const int i : outputs.index_range()) { - BLI_assert(fields_to_variables.contains(fields[i].get())); - builder.add_output_parameter(*fields_to_variables.lookup(fields[i].get())); + public: + void foreach_input(blender::FunctionRef<void(const Field &input)> fn) const final + { + for (const FieldPtr &field : input_fields_) { + fn(*field); + } } - // builder.add_output_parameter(*var4); - - BLI_assert(procedure.validate()); - - /* Evaluate procedure. */ - MFProcedureExecutor executor{"Evaluate Field", procedure}; - MFParamsBuilder params{executor, mask.min_array_size()}; - MFContextBuilder context; - - /* Add the input data. */ - for (blender::Map<const InputField *, GVArrayPtr>::Item item : computed_inputs.items()) { - params.add_readonly_single_input(*item.value); + void foreach_input_recursive(blender::FunctionRef<void(const Field &input)> fn) const final + { + for (const FieldPtr &field : input_fields_) { + fn(*field); + field->foreach_input(fn); + } } - /* Add the output arrays. */ - for (const int i : fields.index_range()) { - BLI_assert(outputs[i].type() == fields[i]->type()); - params.add_uninitialized_single_output(outputs[i]); + const MultiFunction &function() const + { + BLI_assert(function_ != nullptr); + return *function_; } +}; - executor.call(mask, params, context); - - // int input_index = 0; - // for (const int param_index : fn_->param_indices()) { - // fn::MFParamType param_type = fn_->param_type(param_index); - // switch (param_type.category()) { - // case fn::MFParamType::SingleInput: { - // const Field &field = *input_fields_[input_index]; - // FieldOutput &output = scope.add_value(field.evaluate(mask, inputs), __func__); - // params.add_readonly_single_input(output.varray_ref()); - // input_index++; - // break; - // } - // case fn::MFParamType::SingleOutput: { - // const CPPType &type = param_type.data_type().single_type(); - // void *buffer = MEM_mallocN_aligned( - // mask.min_array_size() * type.size(), type.alignment(), __func__); - // GMutableSpan span{type, buffer, mask.min_array_size()}; - // outputs.append(span); - // params.add_uninitialized_single_output(span); - // if (param_index == output_param_index_) { - // output_span_index = outputs.size() - 1; - // } - // break; - // } - // case fn::MFParamType::SingleMutable: - // case fn::MFParamType::VectorInput: - // case fn::MFParamType::VectorMutable: - // case fn::MFParamType::VectorOutput: - // BLI_assert_unreachable(); - // break; - // } - // } -} +/** + * Evaluate more than one field at a time, as an optimization + * in case they share inputs or various intermediate values. + */ +void evaluate_fields(const blender::Span<FieldPtr> fields, + const blender::MutableSpan<GMutableSpan> outputs, + const blender::IndexMask mask); } // namespace blender::fn \ No newline at end of file diff --git a/source/blender/functions/intern/field.cc b/source/blender/functions/intern/field.cc new file mode 100644 index 00000000000..e2c25ac1ad7 --- /dev/null +++ b/source/blender/functions/intern/field.cc @@ -0,0 +1,134 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "FN_field.hh" + +namespace blender::fn { + +static void add_field_parameters(const Field &field, + MFProcedureBuilder &builder, + Map<const Field *, MFVariable *> &variable_map) +{ + if (const MultiFunctionField *mf_field = dynamic_cast<const MultiFunctionField *>(&field)) { + /* Recursively make sure all of the inputs have entries in the parameter map. */ + mf_field->foreach_input_recursive([&](const Field &input_field) { + add_field_parameters(input_field, builder, variable_map); + }); + + /* Gather the immediate inputs to this field. */ + Vector<MFVariable *> inputs; + mf_field->foreach_input( + [&](const Field &input_field) { inputs.append(variable_map.lookup(&input_field)); }); @@ Diff output truncated at 10240 characters. @@ _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org List details, subscription details or unsubscribe: https://lists.blender.org/mailman/listinfo/bf-blender-cvs