[Bf-blender-cvs] [5296f03f9ff] functions: initial generic automatic vectorization, used in Combine Vector node

Jacques Lucke noreply at git.blender.org
Sat Apr 6 18:47:20 CEST 2019


Commit: 5296f03f9ffefc6e64d13462729a9b00a6ce389f
Author: Jacques Lucke
Date:   Sat Apr 6 17:21:07 2019 +0200
Branches: functions
https://developer.blender.org/rB5296f03f9ffefc6e64d13462729a9b00a6ce389f

initial generic automatic vectorization, used in Combine Vector node

===================================================================

M	source/blender/blenlib/BLI_small_vector.hpp
M	source/blender/functions/CMakeLists.txt
M	source/blender/functions/FN_functions.hpp
M	source/blender/functions/backends/tuple_call/tuple_call.hpp
M	source/blender/functions/frontends/data_flow_nodes/inserters/nodes.cpp
A	source/blender/functions/functions/auto_vectorization.cpp
A	source/blender/functions/functions/auto_vectorization.hpp
M	source/blender/functions/functions/vectors.cpp

===================================================================

diff --git a/source/blender/blenlib/BLI_small_vector.hpp b/source/blender/blenlib/BLI_small_vector.hpp
index 025534351d2..c5ffee5dc7a 100644
--- a/source/blender/blenlib/BLI_small_vector.hpp
+++ b/source/blender/blenlib/BLI_small_vector.hpp
@@ -172,6 +172,11 @@ namespace BLI {
 			return -1;
 		}
 
+		bool contains(const T &value) const
+		{
+			return this->index(value) != -1;
+		}
+
 		static bool all_equal(const SmallVector &a, const SmallVector &b)
 		{
 			if (a.size() != b.size()) {
diff --git a/source/blender/functions/CMakeLists.txt b/source/blender/functions/CMakeLists.txt
index d0313d51a7a..098d571e6a0 100644
--- a/source/blender/functions/CMakeLists.txt
+++ b/source/blender/functions/CMakeLists.txt
@@ -116,6 +116,8 @@ set(SRC
 	functions/simple_conversions.cpp
 	functions/switch.hpp
 	functions/switch.cpp
+	functions/auto_vectorization.hpp
+	functions/auto_vectorization.cpp
 
 	frontends/data_flow_nodes/builder.hpp
 	frontends/data_flow_nodes/builder.cpp
diff --git a/source/blender/functions/FN_functions.hpp b/source/blender/functions/FN_functions.hpp
index 4da5b8b27e0..d1090a80f44 100644
--- a/source/blender/functions/FN_functions.hpp
+++ b/source/blender/functions/FN_functions.hpp
@@ -6,4 +6,5 @@
 #include "functions/vectors.hpp"
 #include "functions/lists.hpp"
 #include "functions/simple_conversions.hpp"
-#include "functions/switch.hpp"
\ No newline at end of file
+#include "functions/switch.hpp"
+#include "functions/auto_vectorization.hpp"
\ No newline at end of file
diff --git a/source/blender/functions/backends/tuple_call/tuple_call.hpp b/source/blender/functions/backends/tuple_call/tuple_call.hpp
index 93a01b3bd9d..6f124b0da4a 100644
--- a/source/blender/functions/backends/tuple_call/tuple_call.hpp
+++ b/source/blender/functions/backends/tuple_call/tuple_call.hpp
@@ -33,6 +33,14 @@ namespace FN {
 	public:
 		BLI_COMPOSITION_DECLARATION(TupleCallBody);
 
+		inline void call__setup_stack(Tuple &fn_in, Tuple &fn_out, ExecutionContext &ctx)
+		{
+			TextStackFrame frame(this->owner()->name().c_str());
+			ctx.stack().push(&frame);
+			this->call(fn_in, fn_out, ctx);
+			ctx.stack().pop();
+		}
+
 		virtual void call(Tuple &fn_in, Tuple &fn_out, ExecutionContext &ctx) const = 0;
 	};
 
diff --git a/source/blender/functions/frontends/data_flow_nodes/inserters/nodes.cpp b/source/blender/functions/frontends/data_flow_nodes/inserters/nodes.cpp
index 1ccdcbec38b..f0b9b6d6f1f 100644
--- a/source/blender/functions/frontends/data_flow_nodes/inserters/nodes.cpp
+++ b/source/blender/functions/frontends/data_flow_nodes/inserters/nodes.cpp
@@ -211,14 +211,57 @@ namespace FN { namespace DataFlowNodes {
 		builder.map_sockets(ctx, node, bnode);
 	}
 
+	static bool vectorized_socket_is_list(PointerRNA *ptr, const char *prop_name)
+	{
+		BLI_assert(RNA_string_length(ptr, prop_name) == strlen("BASE"));
+		char value[5];
+		RNA_string_get(ptr, prop_name, value);
+		BLI_assert(STREQ(value, "BASE") || STREQ(value, "LIST"));
+		return STREQ(value, "LIST");
+	}
+
+	static SharedFunction original_or_vectorized(
+		SharedFunction &fn, const SmallVector<bool> vectorized_inputs)
+	{
+		if (vectorized_inputs.contains(true)) {
+			return Functions::auto_vectorization(fn, vectorized_inputs);
+		}
+		else {
+			return fn;
+		}
+	}
+
+	static void insert_combine_vector_node(
+		Builder &builder,
+		const BuilderContext &ctx,
+		bNode *bnode)
+	{
+		PointerRNA ptr;
+		ctx.get_rna(bnode, &ptr);
+
+		SmallVector<bool> vectorized_inputs = {
+			vectorized_socket_is_list(&ptr, "use_list__x"),
+			vectorized_socket_is_list(&ptr, "use_list__y"),
+			vectorized_socket_is_list(&ptr, "use_list__z"),
+		};
+
+		SharedFunction &original_fn = Functions::combine_vector();
+		SharedFunction final_fn = original_or_vectorized(
+			original_fn, vectorized_inputs);
+
+		Node *node = builder.insert_function(final_fn, ctx.btree(), bnode);
+		builder.map_sockets(ctx, node, bnode);
+	}
+
 	void register_node_inserters(GraphInserters &inserters)
 	{
-		inserters.reg_node_function("fn_CombineVectorNode", Functions::combine_vector);
 		inserters.reg_node_function("fn_SeparateVectorNode", Functions::separate_vector);
 		inserters.reg_node_function("fn_VectorDistanceNode", Functions::separate_vector);
 		inserters.reg_node_function("fn_RandomNumberNode", Functions::random_number);
 		inserters.reg_node_function("fn_MapRangeNode", Functions::map_range);
+		//inserters.reg_node_function("fn_CombineVectorNode", Functions::combine_vector);
 
+		inserters.reg_node_inserter("fn_CombineVectorNode", insert_combine_vector_node);
 		inserters.reg_node_inserter("fn_ObjectTransformsNode", insert_object_transforms_node);
 		inserters.reg_node_inserter("fn_FloatMathNode", insert_float_math_node);
 		inserters.reg_node_inserter("fn_VectorMathNode", insert_vector_math_node);
diff --git a/source/blender/functions/functions/auto_vectorization.cpp b/source/blender/functions/functions/auto_vectorization.cpp
new file mode 100644
index 00000000000..31cb2501d8c
--- /dev/null
+++ b/source/blender/functions/functions/auto_vectorization.cpp
@@ -0,0 +1,233 @@
+#include <cmath>
+
+#include "FN_functions.hpp"
+#include "FN_types.hpp"
+#include "FN_tuple_call.hpp"
+
+namespace FN { namespace Functions {
+
+	class AutoVectorization : public TupleCallBody {
+	private:
+		SharedFunction m_main;
+		TupleCallBody *m_main_body;
+
+		const SmallVector<bool> m_input_is_list;
+		SmallVector<uint> m_list_inputs;
+
+		SmallVector<TupleCallBody *> m_get_length_bodies;
+		uint m_max_len_in_size, m_max_len_out_size;
+
+		SmallVector<TupleCallBody *> m_get_element_bodies;
+		SmallVector<TupleCallBody *> m_create_empty_bodies;
+		SmallVector<TupleCallBody *> m_append_bodies;
+
+	public:
+		AutoVectorization(
+			SharedFunction main,
+			const SmallVector<bool> &input_is_list)
+			: m_main(main),
+			  m_main_body(main->body<TupleCallBody>()),
+			  m_input_is_list(input_is_list)
+			{
+				for (uint i = 0; i < input_is_list.size(); i++) {
+					if (input_is_list[i]) {
+						m_list_inputs.append(i);
+					}
+				}
+				for (uint i : m_list_inputs) {
+					SharedType &base_type = main->signature().inputs()[i].type();
+					m_get_length_bodies.append(list_length(base_type)->body<TupleCallBody>());
+					m_get_element_bodies.append(get_list_element(base_type)->body<TupleCallBody>());
+				}
+
+				m_max_len_in_size = 0;
+				m_max_len_out_size = 0;
+				for (TupleCallBody *body : m_get_length_bodies) {
+					m_max_len_in_size = std::max(m_max_len_in_size, body->meta_in()->total_size());
+					m_max_len_out_size = std::max(m_max_len_out_size, body->meta_out()->total_size());
+				}
+
+				for (auto output : main->signature().outputs()) {
+					SharedType &base_type = output.type();
+					m_create_empty_bodies.append(empty_list(base_type)->body<TupleCallBody>());
+					m_append_bodies.append(append_to_list(base_type)->body<TupleCallBody>());
+				}
+			}
+
+		void call(Tuple &fn_in, Tuple &fn_out, ExecutionContext &ctx) const override
+		{
+			uint *input_lengths = BLI_array_alloca(input_lengths, m_list_inputs.size());
+			this->get_input_list_lengths(fn_in, ctx, input_lengths);
+
+			uint max_length = 0;
+			for (uint i = 0; i < m_list_inputs.size(); i++) {
+				max_length = std::max(max_length, input_lengths[i]);
+			}
+
+			ctx.print_with_traceback("Final Length: " + std::to_string(max_length));
+
+			this->initialize_empty_lists(fn_out, ctx);
+
+			FN_TUPLE_STACK_ALLOC(main_in, m_main_body->meta_in());
+			FN_TUPLE_STACK_ALLOC(main_out, m_main_body->meta_out());
+
+			for (uint iteration = 0; iteration < max_length; iteration++) {
+				uint list_index = 0;
+				for (uint i = 0; i < m_input_is_list.size(); i++) {
+					if (m_input_is_list[i]) {
+						this->copy_in_iteration(iteration, fn_in, main_in, i, list_index, input_lengths[list_index], ctx);
+						list_index++;
+					}
+					else {
+						Tuple::copy_element(fn_in, i, main_in, i);
+					}
+				}
+
+				m_main_body->call(main_in, main_out, ctx);
+
+				for (uint i = 0; i < m_main->signature().outputs().size(); i++) {
+					this->append_to_output(main_out, fn_out, i, ctx);
+				}
+			}
+
+			FN_TUPLE_STACK_FREE(main_in);
+			FN_TUPLE_STACK_FREE(main_out);
+		}
+
+	private:
+		void get_input_list_lengths(Tuple &fn_in, ExecutionContext &ctx, uint *r_lengths) const
+		{
+			void *buf_in = alloca(m_max_len_in_size);
+			void *buf_out = alloca(m_max_len_out_size);
+
+			for (uint i = 0; i < m_list_inputs.size(); i++) {
+				uint index = m_list_inputs[i];
+				TupleCallBody *body = m_get_length_bodies[i];
+
+				Tuple &len_in = Tuple::NewInBuffer(body->meta_in(), buf_in);
+				Tuple &len_out = Tuple::NewInBuffer(body->meta_out(), buf_out);
+
+				Tuple::copy_element(fn_in, index, len_in, 0);
+
+				body->call__setup_stack(len_in, len_out, ctx);
+
+				uint length = len_out.get<uint>(0);
+				r_lengths[i] = length;
+
+				len_in.~Tuple();
+				len_out.~Tuple();
+			}
+		}
+
+		void copy_in_iteration(uint iteration, Tuple &fn_in, Tuple &main_in, uint index, uint list_index, uint list_length, ExecutionContext &ctx) const
+		{
+			if (list_length == 0) {
+				main_in.init_default(index);
+				return;
+			}
+
+			TupleCallBody *body = m_get_element_bodies[list_index];
+
+			uint load_index = iteration % list_length;
+			FN_TUPLE_STACK_ALLOC(get_element_in, body->meta_in());
+			FN_TUPLE_STACK_ALLOC(get_element_out, body->meta_out());
+
+			Tuple::copy_element(fn_in, index, get_element_in, 0);
+			get_element_in.set<uint>(1, load_index);
+			get_element_in.init_default(2);
+
+			body->call__setup_stack(get_element_in, get_element_out, ctx);
+
+			Tuple::relocate_element(get_element_out, 0, main_in, index);
+
+			FN_TUPLE_STACK_FREE(get_element_in);
+			FN_TUPLE_STACK_FREE(get_element_out);
+		}
+
+		void initialize_empty_lists(Tuple &fn_out, ExecutionContext &ctx) const
+		{
+			for (uint i = 0; i < m_main->signature().outputs().size(); i++) {
+				this->initialize_empty_list(fn_out, i, ctx);
+			}
+		}
+
+		void initialize_empty_list(Tuple &fn_out, uint index, ExecutionContext &ctx) const
+		{
+			TupleCallBody *body = m_create_empty_bodies[index];
+
+			FN_TUPLE_STACK_ALLOC(create_list_in, body->meta_in());
+			FN_TUPLE_STACK_ALLOC(create_list_out, body->meta_out());
+
+			body->call__setu

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list