1 // This file is part of OpenCV project.
2 // It is subject to the license terms in the LICENSE file found in the top-level directory
3 // of this distribution and at http://opencv.org/license.html.
4 //
5 // Copyright (C) 2018-2020 Intel Corporation
6
7
8 #include "precomp.hpp"
9
10 #include <ade/util/zip_range.hpp> // util::indexed
11 #include <ade/graph.hpp>
12 #include <ade/passes/check_cycles.hpp>
13
14 #include "compiler/gmodel.hpp"
15 #include "compiler/passes/passes.hpp"
16 #include "logger.hpp" // GAPI_LOG
17
18
19 // Iterate over all nodes and initialize meta of objects taken from the
20 // outside (i.e., computation input/output arguments)
initMeta(ade::passes::PassContext & ctx,const GMetaArgs & metas)21 void cv::gimpl::passes::initMeta(ade::passes::PassContext &ctx, const GMetaArgs &metas)
22 {
23 GModel::Graph gr(ctx.graph);
24
25 const auto &proto = gr.metadata().get<Protocol>();
26
27 for (const auto it : ade::util::indexed(proto.in_nhs))
28 {
29 auto& data = gr.metadata(ade::util::value(it)).get<Data>();
30 data.meta = metas.at(ade::util::index(it));
31 }
32 }
33
34 // Iterate over all operations in the topological order, trigger kernels
35 // validate() function, update output objects metadata.
inferMeta(ade::passes::PassContext & ctx,bool meta_is_initialized)36 void cv::gimpl::passes::inferMeta(ade::passes::PassContext &ctx, bool meta_is_initialized)
37 {
38 // FIXME: ADE pass dependency on topo_sort?
39 // FIXME: ADE pass dependency on initMeta?
40 GModel::Graph gr(ctx.graph);
41
42 const auto sorted = gr.metadata().get<ade::passes::TopologicalSortData>() ;
43 for (const auto &nh : sorted.nodes())
44 {
45 if (gr.metadata(nh).get<NodeType>().t == NodeType::OP)
46 {
47 const auto& op = gr.metadata(nh).get<Op>();
48 GAPI_Assert(op.k.outMeta != nullptr);
49
50 // Prepare operation's input metadata vector
51 // Note that it's size is usually different from nh.inEdges.size(),
52 // and its element count is equal to operation's arguments count
53 // (which may contain graph-construction-time parameters like integers, etc)
54 GMetaArgs input_meta_args(op.args.size());
55
56 // Iterate through input edges, update input_meta_args's slots
57 // appropriately. Not all of them will be updated due to (see above).
58 GAPI_Assert(nh->inEdges().size() > 0);
59 for (const auto &in_eh : nh->inEdges())
60 {
61 const auto& input_port = gr.metadata(in_eh).get<Input>().port;
62 const auto& input_nh = in_eh->srcNode();
63 GAPI_Assert(gr.metadata(input_nh).get<NodeType>().t == NodeType::DATA);
64
65 const auto& input_meta = gr.metadata(input_nh).get<Data>().meta;
66 if (util::holds_alternative<util::monostate>(input_meta))
67 {
68 // No meta in an input argument - a fatal error
69 // (note graph is traversed here in topoligcal order)
70 util::throw_error(std::logic_error("Fatal: input object's metadata "
71 "not found!"));
72 // FIXME: Add more details!!!
73 }
74 input_meta_args.at(input_port) = input_meta;
75 }
76
77 // Now ask kernel for it's output meta.
78 // Resulting out_args may have a larger size than op.outs, since some
79 // outputs could stay unused (unconnected)
80 const auto out_metas = gr.metadata(nh).contains<CustomMetaFunction>()
81 ? gr.metadata(nh).get<CustomMetaFunction>().customOutMeta(ctx.graph,
82 nh,
83 input_meta_args,
84 op.args)
85 : op.k.outMeta(input_meta_args, op.args);
86
87 // Walk through operation's outputs, update meta of output objects
88 // appropriately
89 GAPI_Assert(nh->outEdges().size() > 0);
90 for (const auto &out_eh : nh->outEdges())
91 {
92 const auto &output_port = gr.metadata(out_eh).get<Output>().port;
93 const auto &output_nh = out_eh->dstNode();
94 GAPI_Assert(gr.metadata(output_nh).get<NodeType>().t == NodeType::DATA);
95
96 auto &output_meta = gr.metadata(output_nh).get<Data>().meta;
97
98 cv::util::suppress_unused_warning(meta_is_initialized);
99 // FIXME: calling compile() with meta the second time when cannot reshape will lead to error below
100 //if (!meta_is_initialized && !util::holds_alternative<util::monostate>(output_meta))
101 //{
102 // GAPI_LOG_INFO(NULL,
103 // "!!! Output object has an initialized meta - "
104 // "how it is possible today?" << std::endl; );
105 // if (output_meta != out_metas.at(output_port))
106 // {
107 // util::throw_error(std::logic_error("Fatal: meta mismatch"));
108 // // FIXME: New exception type?
109 // // FIXME: More details!
110 // }
111 //}
112 // Store meta in graph
113 output_meta = out_metas.at(output_port);
114 }
115 } // if(OP)
116 } // for(sorted)
117 }
118
119 // After all metadata in graph is inferred, store a vector of inferred metas
120 // for computation output values.
storeResultingMeta(ade::passes::PassContext & ctx)121 void cv::gimpl::passes::storeResultingMeta(ade::passes::PassContext &ctx)
122 {
123 GModel::Graph gr(ctx.graph);
124
125 const auto &proto = gr.metadata().get<Protocol>();
126 GMetaArgs output_metas(proto.out_nhs.size());
127
128 for (const auto it : ade::util::indexed(proto.out_nhs))
129 {
130 auto& data = gr.metadata(ade::util::value(it)).get<Data>();
131 output_metas[ade::util::index(it)] = data.meta;
132 }
133
134 gr.metadata().set(OutputMeta{output_metas});
135 }
136