123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300 |
- // This file is part of OpenCV project.
- // It is subject to the license terms in the LICENSE file found in the top-level directory
- // of this distribution and at http://opencv.org/license.html.
- //
- // Copyright (C) 2018 Intel Corporation
- #include "../test_precomp.hpp"
- #include "../gapi_mock_kernels.hpp"
- namespace opencv_test
- {
- namespace
- {
- class GMockExecutable final: public cv::gimpl::GIslandExecutable
- {
- virtual inline bool canReshape() const override {
- return m_priv->m_can_reshape;
- }
- virtual void reshape(ade::Graph&, const GCompileArgs&) override
- {
- m_priv->m_reshape_counter++;
- }
- virtual void handleNewStream() override { }
- virtual void run(std::vector<InObj>&&, std::vector<OutObj>&&) { }
- virtual bool allocatesOutputs() const override
- {
- return true;
- }
- virtual cv::RMat allocate(const cv::GMatDesc&) const override
- {
- m_priv->m_allocate_counter++;
- return cv::RMat();
- }
- // NB: GMockBackendImpl creates new unique_ptr<GMockExecutable>
- // on every compile call. Need to share counters between instances in order
- // to validate it in tests.
- struct Priv
- {
- bool m_can_reshape;
- int m_reshape_counter;
- int m_allocate_counter;
- };
- std::shared_ptr<Priv> m_priv;
- public:
- GMockExecutable(bool can_reshape = true)
- : m_priv(new Priv{can_reshape, 0, 0})
- {
- };
- void setReshape(bool can_reshape) { m_priv->m_can_reshape = can_reshape; }
- int getReshapeCounter() const { return m_priv->m_reshape_counter; }
- int getAllocateCounter() const { return m_priv->m_allocate_counter; }
- };
- class GMockBackendImpl final: public cv::gapi::GBackend::Priv
- {
- virtual void unpackKernel(ade::Graph &,
- const ade::NodeHandle &,
- const cv::GKernelImpl &) override { }
- virtual EPtr compile(const ade::Graph &,
- const cv::GCompileArgs &,
- const std::vector<ade::NodeHandle> &) const override
- {
- ++m_compile_counter;
- return EPtr{new GMockExecutable(m_exec)};
- }
- mutable int m_compile_counter = 0;
- GMockExecutable m_exec;
- virtual bool controlsMerge() const override {
- return true;
- }
- virtual bool allowsMerge(const cv::gimpl::GIslandModel::Graph &,
- const ade::NodeHandle &,
- const ade::NodeHandle &,
- const ade::NodeHandle &) const override {
- return false;
- }
- public:
- GMockBackendImpl(const GMockExecutable& exec) : m_exec(exec) { };
- int getCompileCounter() const { return m_compile_counter; }
- };
- class GMockFunctor : public gapi::cpu::GOCVFunctor
- {
- public:
- GMockFunctor(cv::gapi::GBackend backend,
- const char* id,
- const Meta &meta,
- const Impl& impl)
- : gapi::cpu::GOCVFunctor(id, meta, impl), m_backend(backend)
- {
- }
- cv::gapi::GBackend backend() const override { return m_backend; }
- private:
- cv::gapi::GBackend m_backend;
- };
- template<typename K, typename Callable>
- GMockFunctor mock_kernel(const cv::gapi::GBackend& backend, Callable c)
- {
- using P = cv::detail::OCVCallHelper<Callable, typename K::InArgs, typename K::OutArgs>;
- return GMockFunctor{ backend
- , K::id()
- , &K::getOutMeta
- , std::bind(&P::callFunctor, std::placeholders::_1, c)
- };
- }
- void dummyFooImpl(const cv::Mat&, cv::Mat&) { };
- void dummyBarImpl(const cv::Mat&, const cv::Mat&, cv::Mat&) { };
- struct GExecutorReshapeTest: public ::testing::Test
- {
- GExecutorReshapeTest()
- : comp([](){
- cv::GMat in;
- cv::GMat out = I::Bar::on(I::Foo::on(in), in);
- return cv::GComputation(in, out);
- })
- {
- backend_impl1 = std::make_shared<GMockBackendImpl>(island1);
- backend1 = cv::gapi::GBackend{backend_impl1};
- backend_impl2 = std::make_shared<GMockBackendImpl>(island2);
- backend2 = cv::gapi::GBackend{backend_impl2};
- auto kernel1 = mock_kernel<I::Foo>(backend1, dummyFooImpl);
- auto kernel2 = mock_kernel<I::Bar>(backend2, dummyBarImpl);
- pkg = cv::gapi::kernels(kernel1, kernel2);
- in_mat1 = cv::Mat::eye(32, 32, CV_8UC1);
- in_mat2 = cv::Mat::eye(64, 64, CV_8UC1);
- }
- cv::GComputation comp;
- GMockExecutable island1;
- std::shared_ptr<GMockBackendImpl> backend_impl1;
- cv::gapi::GBackend backend1;
- GMockExecutable island2;
- std::shared_ptr<GMockBackendImpl> backend_impl2;
- cv::gapi::GBackend backend2;
- cv::GKernelPackage pkg;
- cv::Mat in_mat1, in_mat2, out_mat;;
- };
- } // anonymous namespace
- // FIXME: avoid code duplication
- // The below graph and config is taken from ComplexIslands test suite
- TEST(GExecutor, SmokeTest)
- {
- cv::GMat in[2];
- cv::GMat tmp[4];
- cv::GScalar scl;
- cv::GMat out[2];
- tmp[0] = cv::gapi::bitwise_not(cv::gapi::bitwise_not(in[0]));
- tmp[1] = cv::gapi::boxFilter(in[1], -1, cv::Size(3,3));
- tmp[2] = tmp[0] + tmp[1]; // FIXME: handle tmp[2] = tmp[0]+tmp[2] typo
- scl = cv::gapi::sum(tmp[1]);
- tmp[3] = cv::gapi::medianBlur(tmp[1], 3);
- out[0] = tmp[2] + scl;
- out[1] = cv::gapi::boxFilter(tmp[3], -1, cv::Size(3,3));
- // isl0 #internal1
- // ........................... .........
- // (in1) -> NotNot ->(tmp0) --> Add ---------> (tmp2) --> AddC -------> (out1)
- // :.....................^...: :..^....:
- // : :
- // : :
- // #internal0 : :
- // .....................:......... :
- // (in2) -> Blur -> (tmp1) ----'--> Sum ----> (scl0) ----'
- // :..........:..................: isl1
- // : ..............................
- // `------------> Median -> (tmp3) --> Blur -------> (out2)
- // :............................:
- cv::gapi::island("isl0", cv::GIn(in[0], tmp[1]), cv::GOut(tmp[2]));
- cv::gapi::island("isl1", cv::GIn(tmp[1]), cv::GOut(out[1]));
- cv::Mat in_mat1 = cv::Mat::eye(32, 32, CV_8UC1);
- cv::Mat in_mat2 = cv::Mat::eye(32, 32, CV_8UC1);
- cv::Mat out_gapi[2];
- // Run G-API:
- cv::GComputation(cv::GIn(in[0], in[1]), cv::GOut(out[0], out[1]))
- .apply(cv::gin(in_mat1, in_mat2), cv::gout(out_gapi[0], out_gapi[1]));
- // Run OpenCV
- cv::Mat out_ocv[2];
- {
- cv::Mat ocv_tmp0;
- cv::Mat ocv_tmp1;
- cv::Mat ocv_tmp2;
- cv::Mat ocv_tmp3;
- cv::Scalar ocv_scl;
- ocv_tmp0 = in_mat1; // skip !(!)
- cv::boxFilter(in_mat2, ocv_tmp1, -1, cv::Size(3,3));
- ocv_tmp2 = ocv_tmp0 + ocv_tmp1;
- ocv_scl = cv::sum(ocv_tmp1);
- cv::medianBlur(ocv_tmp1, ocv_tmp3, 3);
- out_ocv[0] = ocv_tmp2 + ocv_scl;
- cv::boxFilter(ocv_tmp3, out_ocv[1], -1, cv::Size(3,3));
- }
- EXPECT_EQ(0, cvtest::norm(out_gapi[0], out_ocv[0], NORM_INF));
- EXPECT_EQ(0, cvtest::norm(out_gapi[1], out_ocv[1], NORM_INF));
- // FIXME: check that GIslandModel has more than 1 island (e.g. fusion
- // with breakdown worked)
- }
- TEST_F(GExecutorReshapeTest, ReshapeInsteadOfRecompile)
- {
- // NB: Initial state
- EXPECT_EQ(0, backend_impl1->getCompileCounter());
- EXPECT_EQ(0, backend_impl2->getCompileCounter());
- EXPECT_EQ(0, island1.getReshapeCounter());
- EXPECT_EQ(0, island2.getReshapeCounter());
- // NB: First compilation.
- comp.apply(cv::gin(in_mat1), cv::gout(out_mat), cv::compile_args(pkg));
- EXPECT_EQ(1, backend_impl1->getCompileCounter());
- EXPECT_EQ(1, backend_impl2->getCompileCounter());
- EXPECT_EQ(0, island1.getReshapeCounter());
- EXPECT_EQ(0, island2.getReshapeCounter());
- // NB: GMockBackendImpl implements "reshape" method,
- // so it won't be recompiled if the meta is changed.
- comp.apply(cv::gin(in_mat2), cv::gout(out_mat), cv::compile_args(pkg));
- EXPECT_EQ(1, backend_impl1->getCompileCounter());
- EXPECT_EQ(1, backend_impl2->getCompileCounter());
- EXPECT_EQ(1, island1.getReshapeCounter());
- EXPECT_EQ(1, island2.getReshapeCounter());
- }
- TEST_F(GExecutorReshapeTest, OneBackendNotReshapable)
- {
- // NB: Make first island not reshapable
- island1.setReshape(false);
- // NB: Initial state
- EXPECT_EQ(0, backend_impl1->getCompileCounter());
- EXPECT_EQ(0, island1.getReshapeCounter());
- EXPECT_EQ(0, backend_impl2->getCompileCounter());
- EXPECT_EQ(0, island2.getReshapeCounter());
- // NB: First compilation.
- comp.apply(cv::gin(in_mat1), cv::gout(out_mat), cv::compile_args(pkg));
- EXPECT_EQ(1, backend_impl1->getCompileCounter());
- EXPECT_EQ(1, backend_impl2->getCompileCounter());
- EXPECT_EQ(0, island1.getReshapeCounter());
- EXPECT_EQ(0, island2.getReshapeCounter());
- // NB: Since one of islands isn't reshapable
- // the entire graph isn't reshapable as well.
- comp.apply(cv::gin(in_mat2), cv::gout(out_mat), cv::compile_args(pkg));
- EXPECT_EQ(2, backend_impl1->getCompileCounter());
- EXPECT_EQ(2, backend_impl2->getCompileCounter());
- EXPECT_EQ(0, island1.getReshapeCounter());
- EXPECT_EQ(0, island2.getReshapeCounter());
- }
- TEST_F(GExecutorReshapeTest, ReshapeCallAllocate)
- {
- // NB: Initial state
- EXPECT_EQ(0, island1.getAllocateCounter());
- EXPECT_EQ(0, island1.getReshapeCounter());
- // NB: First compilation.
- comp.apply(cv::gin(in_mat1), cv::gout(out_mat), cv::compile_args(pkg));
- EXPECT_EQ(1, island1.getAllocateCounter());
- EXPECT_EQ(0, island1.getReshapeCounter());
- // NB: The entire graph is reshapable, so it won't be recompiled, but reshaped.
- // Check that reshape call "allocate" to reallocate buffers.
- comp.apply(cv::gin(in_mat2), cv::gout(out_mat), cv::compile_args(pkg));
- EXPECT_EQ(2, island1.getAllocateCounter());
- EXPECT_EQ(1, island1.getReshapeCounter());
- }
- // FIXME: Add explicit tests on GMat/GScalar/GArray<T> being connectors
- // between executed islands
- } // namespace opencv_test
|