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