From cd56efca3d53792703948e28ae487eee394bbf93 Mon Sep 17 00:00:00 2001 From: Martin Felis Date: Mon, 1 Apr 2024 21:18:26 +0200 Subject: [PATCH] Only storing single socket in AnimGraphConnections and simplified wiring logic. --- src/AnimGraph/AnimGraphBlendTree.cc | 55 ++---------- src/AnimGraph/AnimGraphBlendTree.h | 111 ++++++++++++++----------- src/AnimGraph/AnimGraphData.h | 9 +- src/AnimGraph/AnimGraphNodes.h | 4 +- src/AnimGraph/AnimGraphResource.cc | 40 ++++++--- src/AnimGraph/AnimGraphStateMachine.cc | 17 ++-- src/AnimGraph/AnimNode.h | 2 +- tests/AnimGraphResourceTests.cc | 72 +++++++++------- 8 files changed, 156 insertions(+), 154 deletions(-) diff --git a/src/AnimGraph/AnimGraphBlendTree.cc b/src/AnimGraph/AnimGraphBlendTree.cc index 7ccef9e..f007bb2 100644 --- a/src/AnimGraph/AnimGraphBlendTree.cc +++ b/src/AnimGraph/AnimGraphBlendTree.cc @@ -62,7 +62,8 @@ void AnimGraphBlendTree::UpdateOrderedNodesRecursive(int node_index) { } } -void AnimGraphBlendTree::MarkActiveInputs(const std::vector& input_connections) { +void AnimGraphBlendTree::MarkActiveInputs( + const std::vector& input_connections) { for (size_t i = 0, n = m_nodes.size(); i < n; i++) { if (m_nodes[i]->m_tick_number != m_tick_number) { m_nodes[i]->m_state = AnimNodeEvalState::Deactivated; @@ -93,8 +94,7 @@ void AnimGraphBlendTree::MarkActiveInputs(const std::vector const AnimGraphConnection& input = m_node_input_connections[node_index][j]; if (input.m_source_node != nullptr - && input.m_target_socket.m_type - != SocketType::SocketTypeAnimation) { + && input.m_socket.m_type != SocketType::SocketTypeAnimation) { input.m_source_node->m_state = AnimNodeEvalState::Activated; } } @@ -102,7 +102,8 @@ void AnimGraphBlendTree::MarkActiveInputs(const std::vector } } -void AnimGraphBlendTree::CalcSyncTrack(const std::vector& input_connections) { +void AnimGraphBlendTree::CalcSyncTrack( + const std::vector& input_connections) { for (size_t i = m_eval_ordered_nodes.size() - 1; i >= 0; i--) { AnimNode* node = m_eval_ordered_nodes[i]; if (node->m_state == AnimNodeEvalState::Deactivated) { @@ -162,54 +163,10 @@ void AnimGraphBlendTree::PropagateTimeToNodeInputs(const AnimNode* node) { // Only propagate time updates via animation sockets. if (input_node != nullptr - && node_input_connections[i].m_target_socket.m_type + && node_input_connections[i].m_socket.m_type == SocketType::SocketTypeAnimation && input_node->m_state == AnimNodeEvalState::Activated) { input_node->UpdateTime(node_time_last, node_time_now); } } } - -Socket* AnimGraphBlendTree::GetInputSocket(const std::string& name) { - for (size_t i = 0, n = m_node_output_connections[1].size(); i < n; i++) { - AnimGraphConnection& connection = m_node_output_connections[1][i]; - if (connection.m_source_socket.m_name == name) { - return &connection.m_source_socket; - } - } - - return nullptr; -} - -Socket* AnimGraphBlendTree::GetOutputSocket(const std::string& name) { - for (size_t i = 0, n = m_node_input_connections[0].size(); i < n; i++) { - AnimGraphConnection& connection = m_node_input_connections[0][i]; - if (connection.m_target_socket.m_name == name) { - return &connection.m_target_socket; - } - } - - return nullptr; -} - -const Socket* AnimGraphBlendTree::GetInputSocket(const std::string& name) const { - for (size_t i = 0, n = m_node_output_connections[1].size(); i < n; i++) { - const AnimGraphConnection& connection = m_node_output_connections[1][i]; - if (connection.m_source_socket.m_name == name) { - return &connection.m_source_socket; - } - } - - return nullptr; -} - -const Socket* AnimGraphBlendTree::GetOutputSocket(const std::string& name) const { - for (size_t i = 0, n = m_node_input_connections[0].size(); i < n; i++) { - const AnimGraphConnection& connection = m_node_input_connections[0][i]; - if (connection.m_target_socket.m_name == name) { - return &connection.m_target_socket; - } - } - - return nullptr; -} \ No newline at end of file diff --git a/src/AnimGraph/AnimGraphBlendTree.h b/src/AnimGraph/AnimGraphBlendTree.h index 62c97ec..b37b509 100644 --- a/src/AnimGraph/AnimGraphBlendTree.h +++ b/src/AnimGraph/AnimGraphBlendTree.h @@ -5,6 +5,8 @@ #ifndef ANIMTESTBED_ANIMGRAPHBLENDTREE_H #define ANIMTESTBED_ANIMGRAPHBLENDTREE_H +#include + #include "AnimNode.h" // @@ -17,6 +19,17 @@ struct AnimGraphBlendTree : public AnimNode { std::vector m_eval_ordered_nodes; std::vector > m_node_input_connections; std::vector > m_node_output_connections; + + [[nodiscard]] const std::vector& + GetGraphInputConnections() const { + return m_node_output_connections[1]; + } + + [[nodiscard]] const std::vector& + GetGraphOutputConnections() const { + return m_node_input_connections[0]; + } + std::vector m_animdata_blocks; NodeDescriptorBase* m_node_descriptor = nullptr; char* m_input_buffer = nullptr; @@ -80,9 +93,6 @@ struct AnimGraphBlendTree : public AnimNode { } } - Socket* GetInputSocket(const std::string& name); - Socket* GetOutputSocket(const std::string& name); - const Socket* GetInputSocket(const std::string& name) const; const Socket* GetOutputSocket(const std::string& name) const; @@ -96,17 +106,22 @@ struct AnimGraphBlendTree : public AnimNode { void SetInput(const char* name, T* value_ptr) { m_node_descriptor->SetOutput(name, value_ptr); + std::vector connected_node_indices; + for (int i = 0; i < m_node_output_connections[1].size(); i++) { const AnimGraphConnection& graph_input_connection = m_node_output_connections[1][i]; - if (graph_input_connection.m_source_socket.m_name == name) { - *graph_input_connection.m_target_socket.m_reference.ptr_ptr = value_ptr; + if (graph_input_connection.m_source_socket_name == name) { + *graph_input_connection.m_socket.m_reference.ptr_ptr = value_ptr; } } } /** Sets the address that is used for the specified AnimGraph output Socket. + * + * We update the pointer of the outputting node. We also have to ensure that + * all usages of that output use the same pointer. * * @tparam T Type of the Socket. * @param name Name of the Socket. @@ -114,45 +129,41 @@ struct AnimGraphBlendTree : public AnimNode { */ template void SetOutput(const char* name, T* value_ptr) { - m_node_descriptor->SetInput(name, value_ptr); + const auto& graph_output_connection = std::find_if( + GetGraphOutputConnections().begin(), + GetGraphOutputConnections().end(), + [&name](const AnimGraphConnection& connection) { + return connection.m_target_socket_name == name; + }); - for (int i = 0; i < m_node_input_connections[0].size(); i++) { - const AnimGraphConnection& graph_output_connection = - m_node_input_connections[0][i]; + if (graph_output_connection == GetGraphOutputConnections().end()) { + std::cerr << "Error: could not find graph connection to output socket " + << name << "." << std::endl; + return; + } - if (graph_output_connection.m_target_socket.m_name == name) { - if (graph_output_connection.m_source_node == m_nodes[1] - && graph_output_connection.m_target_node == m_nodes[0]) { - std::cerr - << "Error: cannot set output for direct graph input to graph " - "output connections. Use GetOutptPtr for output instead!" - << std::endl; + if (graph_output_connection->m_source_node == m_nodes[1] + && graph_output_connection->m_target_node == m_nodes[0]) { + std::cerr << "Error: cannot set output for direct graph input to graph " + "output connections. Use GetOutptPtr for output instead!" + << std::endl; - return; - } + return; + } - *graph_output_connection.m_source_socket.m_reference.ptr_ptr = - value_ptr; + size_t output_node_index = + GetAnimNodeIndex(graph_output_connection->m_source_node); - // Make sure all other output connections of this pin use the same output pointer - int source_node_index = - GetAnimNodeIndex(graph_output_connection.m_source_node); - for (int j = 0; j < m_node_output_connections[source_node_index].size(); - j++) { - const AnimGraphConnection& source_output_connection = - m_node_output_connections[source_node_index][j]; - if (source_output_connection.m_target_node == m_nodes[0]) { - continue; - } - - if (source_output_connection.m_source_socket.m_name - == graph_output_connection.m_source_socket.m_name) { - *source_output_connection.m_target_socket.m_reference.ptr_ptr = - value_ptr; - } - } + const std::vector& node_output_connections = + m_node_output_connections[output_node_index]; + for (const AnimGraphConnection& connection : node_output_connections) { + if (connection.m_source_socket_name + == graph_output_connection->m_source_socket_name) { + *connection.m_socket.m_reference.ptr_ptr = value_ptr; } } + + *graph_output_connection->m_socket.m_reference.ptr_ptr = value_ptr; } /** Returns the address that is used for the specified AnimGraph output Socket. @@ -169,9 +180,9 @@ struct AnimGraphBlendTree : public AnimNode { for (int i = 0; i < m_node_input_connections[0].size(); i++) { const AnimGraphConnection& graph_output_connection = m_node_input_connections[0][i]; - if (graph_output_connection.m_target_socket.m_name == name) { - return static_cast( - *graph_output_connection.m_source_socket.m_reference.ptr_ptr); + if (graph_output_connection.m_target_socket_name == name) { + return static_cast( + *graph_output_connection.m_socket.m_reference.ptr_ptr); } } @@ -179,18 +190,24 @@ struct AnimGraphBlendTree : public AnimNode { } void* GetInputPtr(const std::string& name) const { - const Socket* input_socket = GetInputSocket(name); - if (input_socket != nullptr) { - return input_socket->m_reference.ptr; + const std::vector graph_input_connections = + GetGraphInputConnections(); + for (const AnimGraphConnection& connection : graph_input_connections) { + if (connection.m_source_socket_name == name) { + return connection.m_socket.m_reference.ptr; + } } return nullptr; } void* GetOutputPtr(const std::string& name) const { - const Socket* input_socket = GetOutputSocket(name); - if (input_socket != nullptr) { - return input_socket->m_reference.ptr; + const std::vector graph_output_connections = + GetGraphOutputConnections(); + for (const AnimGraphConnection& connection : graph_output_connections) { + if (connection.m_source_socket_name == name) { + return connection.m_socket.m_reference.ptr; + } } return nullptr; @@ -213,7 +230,7 @@ struct AnimGraphBlendTree : public AnimNode { const std::vector& input_connection = m_node_input_connections[node_index]; for (size_t i = 0, n = input_connection.size(); i < n; i++) { - if (input_connection[i].m_target_socket.m_name == input_name) { + if (input_connection[i].m_target_socket_name == input_name) { return input_connection[i].m_source_node; } } diff --git a/src/AnimGraph/AnimGraphData.h b/src/AnimGraph/AnimGraphData.h index 6584893..9486545 100644 --- a/src/AnimGraph/AnimGraphData.h +++ b/src/AnimGraph/AnimGraphData.h @@ -262,13 +262,13 @@ SocketType GetSocketType() { struct AnimGraphConnection { AnimNode* m_source_node = nullptr; - Socket m_source_socket; + std::string m_source_socket_name = ""; AnimNode* m_target_node = nullptr; - Socket m_target_socket; + std::string m_target_socket_name = ""; + Socket m_socket; bool m_crosses_hierarchy = false; }; - struct NodeDescriptorBase { std::vector m_inputs; std::vector m_outputs; @@ -431,7 +431,8 @@ struct NodeDescriptorBase { return nullptr; } - const Socket* FindSocket(const char* name, const std::vector& sockets) const { + const Socket* FindSocket(const char* name, const std::vector& sockets) + const { for (int i = 0, n = sockets.size(); i < n; i++) { if (sockets[i].m_name == name) { return &sockets[i]; diff --git a/src/AnimGraph/AnimGraphNodes.h b/src/AnimGraph/AnimGraphNodes.h index 63ee36c..c7ef514 100644 --- a/src/AnimGraph/AnimGraphNodes.h +++ b/src/AnimGraph/AnimGraphNodes.h @@ -32,12 +32,12 @@ struct Blend2Node : public AnimNode { continue; } - if (input.m_target_socket.m_name == "Input0" && *i_blend_weight < 0.999) { + if (input.m_target_socket_name == "Input0" && *i_blend_weight < 0.999) { input_node->m_state = AnimNodeEvalState::Activated; continue; } - if (input.m_target_socket.m_name == "Input1" && *i_blend_weight > 0.001) { + if (input.m_target_socket_name == "Input1" && *i_blend_weight > 0.001) { input_node->m_state = AnimNodeEvalState::Activated; continue; } diff --git a/src/AnimGraph/AnimGraphResource.cc b/src/AnimGraph/AnimGraphResource.cc index b55eac7..c55ec47 100644 --- a/src/AnimGraph/AnimGraphResource.cc +++ b/src/AnimGraph/AnimGraphResource.cc @@ -658,9 +658,15 @@ void AnimGraphResource::CreateBlendTreeConnectionInstances( // subgraph. AnimGraphConnection embedded_graph_activation_connection; embedded_graph_activation_connection.m_source_node = source_node; - embedded_graph_activation_connection.m_source_socket = *source_socket; + embedded_graph_activation_connection.m_source_socket_name = + source_socket->m_name; embedded_graph_activation_connection.m_target_node = target_node; - embedded_graph_activation_connection.m_target_socket = *target_socket; + embedded_graph_activation_connection.m_target_socket_name = + target_socket->m_name; + + // TODO: what to set the pointer to?!? + embedded_graph_activation_connection.m_socket = *target_socket; + instance.m_node_input_connections[connection.target_node_index].push_back( embedded_graph_activation_connection); instance.m_node_output_connections[connection.source_node_index] @@ -702,7 +708,7 @@ void AnimGraphResource::CreateBlendTreeConnectionInstances( for (size_t j = 0; j < embeded_target_node_inputs.size(); j++) { AnimGraphConnection& embedded_target_connection = embeded_target_node_inputs[j]; - if (embedded_target_connection.m_source_socket.m_name + if (embedded_target_connection.m_source_socket_name == target_socket->m_name) { embedded_target_connection.m_source_node = source_node; embedded_target_connection.m_crosses_hierarchy = true; @@ -711,27 +717,35 @@ void AnimGraphResource::CreateBlendTreeConnectionInstances( // connection in the parent blend tree. That way // parent_tree.SetValue<>() correctly propagates the value to the // embedded node socket. - target_socket = &embedded_target_connection.m_target_socket; + target_socket = &embedded_target_connection.m_socket; } } } instance_connection.m_source_node = source_node; - instance_connection.m_source_socket = *source_socket; + instance_connection.m_source_socket_name = source_socket->m_name; instance_connection.m_target_node = target_node; - instance_connection.m_target_socket = *target_socket; + instance_connection.m_target_socket_name = target_socket->m_name; + instance_connection.m_socket = *target_socket; + + if (connection.source_node_index == 1) { + instance_connection.m_socket = *target_socket; + } else if (connection.target_node_index == 0) { + instance_connection.m_socket = *source_socket; + } else { + *target_socket->m_reference.ptr_ptr = + &instance.m_connection_data_storage[connection_data_offset]; + *source_socket->m_reference.ptr_ptr = + &instance.m_connection_data_storage[connection_data_offset]; + } + instance.m_node_input_connections[connection.target_node_index].push_back( instance_connection); instance.m_node_output_connections[connection.source_node_index].push_back( instance_connection); - source_node_descriptor->SetOutputUnchecked( - connection.source_socket_name.c_str(), - &instance.m_connection_data_storage[connection_data_offset]); - - target_node_descriptor->SetInputUnchecked( - connection.target_socket_name.c_str(), - &instance.m_connection_data_storage[connection_data_offset]); + *instance_connection.m_socket.m_reference.ptr_ptr = + &instance.m_connection_data_storage[connection_data_offset]; if (source_socket->m_type == SocketType::SocketTypeAnimation) { instance.m_animdata_blocks.push_back( diff --git a/src/AnimGraph/AnimGraphStateMachine.cc b/src/AnimGraph/AnimGraphStateMachine.cc index a910f46..b61662a 100644 --- a/src/AnimGraph/AnimGraphStateMachine.cc +++ b/src/AnimGraph/AnimGraphStateMachine.cc @@ -5,21 +5,24 @@ #include "AnimGraphStateMachine.h" bool AnimGraphStateMachine::Init(AnimGraphContext& context) { - + assert(false && !"Not yet implemented!"); + return false; } -void AnimGraphStateMachine::MarkActiveInputs(const std::vector& input_connections) { - +void AnimGraphStateMachine::MarkActiveInputs( + const std::vector& input_connections) { + assert(false && !"Not yet implemented!"); } -void AnimGraphStateMachine::CalcSyncTrack(const std::vector& input_connections) { - +void AnimGraphStateMachine::CalcSyncTrack( + const std::vector& input_connections) { + assert(false && !"Not yet implemented!"); } void AnimGraphStateMachine::UpdateTime(float time_last, float time_now) { - + assert(false && !"Not yet implemented!"); } void AnimGraphStateMachine::Evaluate(AnimGraphContext& context) { - + assert(false && !"Not yet implemented!"); } \ No newline at end of file diff --git a/src/AnimGraph/AnimNode.h b/src/AnimGraph/AnimNode.h index d9ecea8..5f7b8bd 100644 --- a/src/AnimGraph/AnimNode.h +++ b/src/AnimGraph/AnimNode.h @@ -56,7 +56,7 @@ struct AnimNode { for (const auto& input : input_connections) { AnimNode* input_node = input.m_source_node; if (input_node != nullptr - && input.m_source_socket.m_type == SocketType::SocketTypeAnimation + && input.m_socket.m_type == SocketType::SocketTypeAnimation && input_node->m_state != AnimNodeEvalState::Deactivated) { m_sync_track = input_node->m_sync_track; return; diff --git a/tests/AnimGraphResourceTests.cc b/tests/AnimGraphResourceTests.cc index 020b2d7..6447560 100644 --- a/tests/AnimGraphResourceTests.cc +++ b/tests/AnimGraphResourceTests.cc @@ -754,17 +754,14 @@ TEST_CASE_METHOD( CHECK(blend2_instance->i_input0 == anim_sampler_walk->o_output); CHECK(blend2_instance->i_input1 == anim_sampler_run->o_output); - const Socket* graph_output_socket = - blend_tree_graph.GetOutputSocket("GraphOutput"); - AnimData* graph_output = - static_cast(*graph_output_socket->m_reference.ptr_ptr); + AnimData* graph_output = static_cast( + blend_tree_graph.GetOutputPtr("GraphOutput")); CHECK( graph_output->m_local_matrices.size() == graph_context.m_skeleton->num_soa_joints()); - CHECK( - blend2_instance->o_output == *graph_output_socket->m_reference.ptr_ptr); + CHECK(blend2_instance->o_output == graph_output); } graph_context.freeAnimations(); @@ -811,39 +808,40 @@ TEST_CASE("ResourceSaveLoadMathGraphInputs", "[AnimGraphResource]") { "GraphVec3Output", nullptr); - AnimNodeResource* graph_input_node = blend_tree_resource.GetGraphInputNode(); - graph_input_node->m_socket_accessor->RegisterOutput( + AnimNodeResource* graph_input_node_resource = + blend_tree_resource.GetGraphInputNode(); + graph_input_node_resource->m_socket_accessor->RegisterOutput( "GraphFloatInput", nullptr); // Prepare graph inputs and outputs - AnimNodeResource* float_to_vec3_node = + AnimNodeResource* float_to_vec3_node_resource = blend_tree_resource.m_nodes[float_to_vec3_node_index]; REQUIRE(blend_tree_resource.ConnectSockets( - graph_input_node, + graph_input_node_resource, "GraphFloatInput", graph_output_node, "GraphFloatOutput")); REQUIRE(blend_tree_resource.ConnectSockets( - graph_input_node, + graph_input_node_resource, "GraphFloatInput", - float_to_vec3_node, + float_to_vec3_node_resource, "Input0")); REQUIRE(blend_tree_resource.ConnectSockets( - graph_input_node, + graph_input_node_resource, "GraphFloatInput", - float_to_vec3_node, + float_to_vec3_node_resource, "Input1")); REQUIRE(blend_tree_resource.ConnectSockets( - graph_input_node, + graph_input_node_resource, "GraphFloatInput", - float_to_vec3_node, + float_to_vec3_node_resource, "Input2")); REQUIRE(blend_tree_resource.ConnectSockets( - float_to_vec3_node, + float_to_vec3_node_resource, "Output", graph_output_node, "GraphVec3Output")); @@ -869,7 +867,7 @@ TEST_CASE("ResourceSaveLoadMathGraphInputs", "[AnimGraphResource]") { == graph_loaded_output_node->m_socket_accessor->m_inputs.size()); REQUIRE( - graph_input_node->m_socket_accessor->m_outputs.size() + graph_input_node_resource->m_socket_accessor->m_outputs.size() == graph_loaded_input_node->m_socket_accessor->m_outputs.size()); REQUIRE( @@ -890,14 +888,17 @@ TEST_CASE("ResourceSaveLoadMathGraphInputs", "[AnimGraphResource]") { AnimGraphBlendTree blend_tree_node; graph_resource_loaded.CreateBlendTreeInstance(blend_tree_node); - REQUIRE(blend_tree_node.GetInputSocket("GraphFloatInput") != nullptr); - REQUIRE( - blend_tree_node.GetInputPtr("GraphFloatInput") - == blend_tree_node.m_input_buffer); - float graph_float_input = 123.456f; blend_tree_node.SetInput("GraphFloatInput", &graph_float_input); + MathFloatToVec3Node* float_to_vec3_node = + dynamic_cast( + blend_tree_node.m_nodes[float_to_vec3_node_index]); + + CHECK(float_to_vec3_node->i_input0 == &graph_float_input); + CHECK(float_to_vec3_node->i_input1 == &graph_float_input); + CHECK(float_to_vec3_node->i_input2 == &graph_float_input); + AND_WHEN("Evaluating Graph") { AnimGraphContext context; context.m_graph = nullptr; @@ -928,6 +929,19 @@ TEST_CASE("ResourceSaveLoadMathGraphInputs", "[AnimGraphResource]") { } } +// +// Graph: +// Input: float GraphFloatInputSingle +// Output: float GraphFloat0Output +// float GraphFloat1Output +// float GraphFloat1Output +// Nodes: 2x Add Node +// Connections: +// - Direct GraphFloatInputSingle to GraphFQloat0Output +// - Remaining wires such that +// GraphFloat1Output -> GraphFLoatInputSingle * 2 +// GraphFloat1Output -> GraphFLoatInputSingle * 3 +// TEST_CASE("SimpleMathEvaluations", "[AnimGraphResource]") { AnimGraphResource graph_resource_origin; graph_resource_origin.m_name = "TestSimpleMathGraph"; @@ -1025,11 +1039,6 @@ TEST_CASE("SimpleMathEvaluations", "[AnimGraphResource]") { AnimGraphBlendTree blend_tree; graph_resource_loaded.CreateBlendTreeInstance(blend_tree); - REQUIRE(blend_tree.GetInputSocket("GraphFloatInput") != nullptr); - REQUIRE( - blend_tree.GetInputPtr("GraphFloatInput") - == blend_tree.m_input_buffer); - float graph_float_input = 123.456f; blend_tree.SetInput("GraphFloatInput", &graph_float_input); @@ -1037,12 +1046,13 @@ TEST_CASE("SimpleMathEvaluations", "[AnimGraphResource]") { AnimGraphContext context; context.m_graph = nullptr; + float float1_output = -1.f; + float float2_output = -1.f; + // float0 output is directly connected to the graph input, therefore // we have to get a ptr to the input data here. float* float0_output_ptr = blend_tree.GetOutputPtr("GraphFloat0Output"); - float float1_output = -1.f; - float float2_output = -1.f; blend_tree.SetOutput("GraphFloat1Output", &float1_output); blend_tree.SetOutput("GraphFloat2Output", &float2_output); @@ -1051,7 +1061,7 @@ TEST_CASE("SimpleMathEvaluations", "[AnimGraphResource]") { blend_tree.Evaluate(context); THEN("output vector components equal the graph input vaulues") { - CHECK(*float0_output_ptr == Approx(graph_float_input)); + CHECK(float0_output_ptr == &graph_float_input); CHECK(float1_output == Approx(graph_float_input * 2.f)); REQUIRE_THAT( float2_output,