// 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 #include "gapi_mock_kernels.hpp" #include // cpu::backend #include // fluid::backend namespace opencv_test { namespace { namespace I { G_TYPED_KERNEL(GClone, , "org.opencv.test.clone") { static GMatDesc outMeta(GMatDesc in) { return in; } }; } enum class KernelTags { CPU_CUSTOM_BGR2GRAY, CPU_CUSTOM_CLONE, CPU_CUSTOM_ADD, FLUID_CUSTOM_BGR2GRAY, FLUID_CUSTOM_CLONE, FLUID_CUSTOM_ADD }; class HeteroGraph: public ::testing::Test { public: HeteroGraph() { auto tmp = I::GClone::on(cv::gapi::add(in[0], in[1])); out = cv::gapi::imgproc::GBGR2Gray::on(tmp); } static void registerCallKernel(KernelTags kernel_tag) { kernel_calls.insert(kernel_tag); } bool checkCallKernel(KernelTags kernel_tag) { return ade::util::contains(kernel_calls, kernel_tag); } protected: void SetUp() override { if (!kernel_calls.empty()) cv::util::throw_error(std::logic_error("Kernel call log has not been cleared!!!")); } void TearDown() override { kernel_calls.clear(); } protected: cv::GMat in[2], out; static std::set kernel_calls; }; namespace cpu { GAPI_OCV_KERNEL(GClone, I::GClone) { static void run(const cv::Mat&, cv::Mat) { HeteroGraph::registerCallKernel(KernelTags::CPU_CUSTOM_CLONE); } }; GAPI_OCV_KERNEL(BGR2Gray, cv::gapi::imgproc::GBGR2Gray) { static void run(const cv::Mat&, cv::Mat&) { HeteroGraph::registerCallKernel(KernelTags::CPU_CUSTOM_BGR2GRAY); } }; GAPI_OCV_KERNEL(GAdd, cv::gapi::core::GAdd) { static void run(const cv::Mat&, const cv::Mat&, int, cv::Mat&) { HeteroGraph::registerCallKernel(KernelTags::CPU_CUSTOM_ADD); } }; } namespace fluid { GAPI_FLUID_KERNEL(GClone, I::GClone, false) { static const int Window = 1; static void run(const cv::gapi::fluid::View&, cv::gapi::fluid::Buffer) { HeteroGraph::registerCallKernel(KernelTags::FLUID_CUSTOM_CLONE); } }; GAPI_FLUID_KERNEL(BGR2Gray, cv::gapi::imgproc::GBGR2Gray, false) { static const int Window = 1; static void run(const cv::gapi::fluid::View&, cv::gapi::fluid::Buffer&) { HeteroGraph::registerCallKernel(KernelTags::FLUID_CUSTOM_BGR2GRAY); } }; GAPI_FLUID_KERNEL(GAdd, cv::gapi::core::GAdd, false) { static const int Window = 1; static void run(const cv::gapi::fluid::View&, const cv::gapi::fluid::View&, int, cv::gapi::fluid::Buffer&) { HeteroGraph::registerCallKernel(KernelTags::FLUID_CUSTOM_ADD); } }; } std::set HeteroGraph::kernel_calls; } // anonymous namespace TEST(KernelPackage, Create) { namespace J = Jupiter; auto pkg = cv::gapi::kernels(); EXPECT_EQ(3u, pkg.size()); } TEST(KernelPackage, Includes) { namespace J = Jupiter; auto pkg = cv::gapi::kernels(); EXPECT_TRUE (pkg.includes()); EXPECT_TRUE (pkg.includes()); EXPECT_TRUE (pkg.includes()); EXPECT_FALSE(pkg.includes()); } TEST(KernelPackage, IncludesAPI) { namespace J = Jupiter; namespace S = Saturn; auto pkg = cv::gapi::kernels(); EXPECT_TRUE (pkg.includesAPI()); EXPECT_TRUE (pkg.includesAPI()); EXPECT_FALSE(pkg.includesAPI()); EXPECT_FALSE(pkg.includesAPI()); } TEST(KernelPackage, Include_Add) { namespace J = Jupiter; auto pkg = cv::gapi::kernels(); EXPECT_FALSE(pkg.includes()); pkg.include(); EXPECT_TRUE(pkg.includes()); } TEST(KernelPackage, Include_REPLACE) { namespace J = Jupiter; namespace S = Saturn; auto pkg = cv::gapi::kernels(); EXPECT_FALSE(pkg.includes()); pkg.include(); EXPECT_FALSE(pkg.includes()); EXPECT_TRUE(pkg.includes()); } TEST(KernelPackage, RemoveBackend) { namespace J = Jupiter; namespace S = Saturn; auto pkg = cv::gapi::kernels(); EXPECT_TRUE(pkg.includes()); EXPECT_TRUE(pkg.includes()); pkg.remove(J::backend()); EXPECT_FALSE(pkg.includes()); EXPECT_FALSE(pkg.includes()); EXPECT_TRUE(pkg.includes()); }; TEST(KernelPackage, RemoveAPI) { namespace J = Jupiter; namespace S = Saturn; auto pkg = cv::gapi::kernels(); EXPECT_TRUE(pkg.includes()); EXPECT_TRUE(pkg.includes()); pkg.remove(); EXPECT_TRUE(pkg.includes()); EXPECT_FALSE(pkg.includes()); }; TEST(KernelPackage, CreateHetero) { namespace J = Jupiter; namespace S = Saturn; auto pkg = cv::gapi::kernels(); EXPECT_EQ(4u, pkg.size()); } TEST(KernelPackage, IncludesHetero) { namespace J = Jupiter; namespace S = Saturn; auto pkg = cv::gapi::kernels(); EXPECT_TRUE (pkg.includes()); EXPECT_TRUE (pkg.includes()); EXPECT_TRUE (pkg.includes()); EXPECT_FALSE(pkg.includes()); EXPECT_TRUE (pkg.includes()); } TEST(KernelPackage, IncludeHetero) { namespace J = Jupiter; namespace S = Saturn; auto pkg = cv::gapi::kernels(); EXPECT_FALSE(pkg.includes()); EXPECT_FALSE(pkg.includes()); pkg.include(); EXPECT_FALSE(pkg.includes()); EXPECT_TRUE (pkg.includes()); } TEST(KernelPackage, Combine_REPLACE_Full) { namespace J = Jupiter; namespace S = Saturn; auto j_pkg = cv::gapi::kernels(); auto s_pkg = cv::gapi::kernels(); auto u_pkg = cv::gapi::combine(j_pkg, s_pkg); EXPECT_EQ(3u, u_pkg.size()); EXPECT_FALSE(u_pkg.includes()); EXPECT_FALSE(u_pkg.includes()); EXPECT_FALSE(u_pkg.includes()); EXPECT_TRUE (u_pkg.includes()); EXPECT_TRUE (u_pkg.includes()); EXPECT_TRUE (u_pkg.includes()); } TEST(KernelPackage, Combine_REPLACE_Partial) { namespace J = Jupiter; namespace S = Saturn; auto j_pkg = cv::gapi::kernels(); auto s_pkg = cv::gapi::kernels(); auto u_pkg = cv::gapi::combine(j_pkg, s_pkg); EXPECT_EQ(2u, u_pkg.size()); EXPECT_TRUE (u_pkg.includes()); EXPECT_FALSE(u_pkg.includes()); EXPECT_TRUE (u_pkg.includes()); } TEST(KernelPackage, Combine_REPLACE_Append) { namespace J = Jupiter; namespace S = Saturn; auto j_pkg = cv::gapi::kernels(); auto s_pkg = cv::gapi::kernels(); auto u_pkg = cv::gapi::combine(j_pkg, s_pkg); EXPECT_EQ(3u, u_pkg.size()); EXPECT_TRUE(u_pkg.includes()); EXPECT_TRUE(u_pkg.includes()); EXPECT_TRUE(u_pkg.includes()); } TEST(KernelPackage, TestWithEmptyLHS) { namespace J = Jupiter; auto lhs = cv::gapi::kernels<>(); auto rhs = cv::gapi::kernels(); auto pkg = cv::gapi::combine(lhs, rhs); EXPECT_EQ(1u, pkg.size()); EXPECT_TRUE(pkg.includes()); } TEST(KernelPackage, TestWithEmptyRHS) { namespace J = Jupiter; auto lhs = cv::gapi::kernels(); auto rhs = cv::gapi::kernels<>(); auto pkg = cv::gapi::combine(lhs, rhs); EXPECT_EQ(1u, pkg.size()); EXPECT_TRUE(pkg.includes()); } TEST(KernelPackage, Return_Unique_Backends) { auto pkg = cv::gapi::kernels(); EXPECT_EQ(2u, pkg.backends().size()); } TEST(KernelPackage, Can_Use_Custom_Kernel) { cv::GMat in[2]; auto out = I::GClone::on(cv::gapi::add(in[0], in[1])); const auto in_meta = cv::GMetaArg(cv::GMatDesc{CV_8U,1,cv::Size(32,32)}); auto pkg = cv::gapi::kernels(); EXPECT_NO_THROW(cv::GComputation(cv::GIn(in[0], in[1]), cv::GOut(out)). compile({in_meta, in_meta}, cv::compile_args(pkg))); } TEST(KernelPackage, CombineMultiple) { namespace J = Jupiter; namespace S = Saturn; auto a = cv::gapi::kernels(); auto b = cv::gapi::kernels(); auto c = cv::gapi::kernels(); auto pkg = cv::gapi::combine(a, b, c); EXPECT_EQ(3u, pkg.size()); EXPECT_TRUE(pkg.includes()); EXPECT_TRUE(pkg.includes()); EXPECT_TRUE(pkg.includes()); } TEST_F(HeteroGraph, Call_Custom_Kernel_Default_Backend) { // in0 -> GCPUAdd -> tmp -> cpu::GClone -> GCPUBGR2Gray -> out // ^ // | // in1 -------` cv::Mat in_mat1 = cv::Mat::eye(3, 3, CV_8UC3), in_mat2 = cv::Mat::eye(3, 3, CV_8UC3), out_mat; auto pkg = cv::gapi::kernels(); cv::GComputation(cv::GIn(in[0], in[1]), cv::GOut(out)). apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat), cv::compile_args(pkg)); EXPECT_TRUE(checkCallKernel(KernelTags::CPU_CUSTOM_CLONE)); } TEST_F(HeteroGraph, Call_Custom_Kernel_Not_Default_Backend) { // in0 -> GCPUAdd -> tmp -> fluid::GClone -> GCPUBGR2Gray -> out // ^ // | // in1 -------` cv::Mat in_mat1 = cv::Mat::eye(3, 3, CV_8UC3), in_mat2 = cv::Mat::eye(3, 3, CV_8UC3), out_mat; auto pkg = cv::gapi::kernels(); cv::GComputation(cv::GIn(in[0], in[1]), cv::GOut(out)). apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat), cv::compile_args(pkg)); EXPECT_TRUE(checkCallKernel(KernelTags::FLUID_CUSTOM_CLONE)); } TEST_F(HeteroGraph, Replace_Default_To_Same_Backend) { // in0 -> GCPUAdd -> tmp -> cpu::GClone -> cpu::BGR2Gray -> out // ^ // | // in1 -------` cv::Mat in_mat1 = cv::Mat::eye(3, 3, CV_8UC3), in_mat2 = cv::Mat::eye(3, 3, CV_8UC3), out_mat; auto pkg = cv::gapi::kernels(); cv::GComputation(cv::GIn(in[0], in[1]), cv::GOut(out)). apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat), cv::compile_args(pkg)); EXPECT_TRUE(checkCallKernel(KernelTags::CPU_CUSTOM_BGR2GRAY)); } TEST_F(HeteroGraph, Replace_Default_To_Another_Backend) { //in0 -> GCPUAdd -> tmp -> cpu::GClone -> fluid::BGR2Gray -> out // ^ // | //in1 --------` cv::Mat in_mat1(300, 300, CV_8UC3), in_mat2(300, 300, CV_8UC3), out_mat; auto pkg = cv::gapi::kernels(); cv::GComputation(cv::GIn(in[0], in[1]), cv::GOut(out)). apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat), cv::compile_args(pkg)); EXPECT_TRUE(checkCallKernel(KernelTags::FLUID_CUSTOM_BGR2GRAY)); } TEST_F(HeteroGraph, Use_Only_Same_Backend) { //in0 -> cpu::GAdd -> tmp -> cpu::GClone -> cpu::BGR2Gray -> out // ^ // | //in1 --------` cv::Mat in_mat1(300, 300, CV_8UC3), in_mat2(300, 300, CV_8UC3), out_mat; auto pkg = cv::gapi::kernels(); cv::GComputation(cv::GIn(in[0], in[1]), cv::GOut(out)). apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat), cv::compile_args(cv::gapi::use_only{pkg})); EXPECT_TRUE(checkCallKernel(KernelTags::CPU_CUSTOM_ADD)); EXPECT_TRUE(checkCallKernel(KernelTags::CPU_CUSTOM_CLONE)); EXPECT_TRUE(checkCallKernel(KernelTags::CPU_CUSTOM_BGR2GRAY)); } TEST_F(HeteroGraph, Use_Only_Another_Backend) { //in0 -> fluid::GAdd -> tmp -> fluid::GClone -> fluid::BGR2Gray -> out // ^ // | //in1 --------` cv::Mat in_mat1(300, 300, CV_8UC3), in_mat2(300, 300, CV_8UC3), out_mat; auto pkg = cv::gapi::kernels(); cv::GComputation(cv::GIn(in[0], in[1]), cv::GOut(out)). apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat), cv::compile_args(cv::gapi::use_only{pkg})); EXPECT_TRUE(checkCallKernel(KernelTags::FLUID_CUSTOM_ADD)); EXPECT_TRUE(checkCallKernel(KernelTags::FLUID_CUSTOM_CLONE)); EXPECT_TRUE(checkCallKernel(KernelTags::FLUID_CUSTOM_BGR2GRAY)); } TEST_F(HeteroGraph, Use_Only_Hetero_Backend) { //in0 -> cpu::GAdd -> tmp -> fluid::GClone -> fluid::BGR2Gray -> out // ^ // | //in1 --------` cv::Mat in_mat1(300, 300, CV_8UC3), in_mat2(300, 300, CV_8UC3), out_mat; auto pkg = cv::gapi::kernels(); cv::GComputation(cv::GIn(in[0], in[1]), cv::GOut(out)). apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat), cv::compile_args(cv::gapi::use_only{pkg})); EXPECT_TRUE(checkCallKernel(KernelTags::CPU_CUSTOM_ADD)); EXPECT_TRUE(checkCallKernel(KernelTags::FLUID_CUSTOM_CLONE)); EXPECT_TRUE(checkCallKernel(KernelTags::FLUID_CUSTOM_BGR2GRAY)); } TEST_F(HeteroGraph, Use_Only_Not_Found_Default) { //in0 -> GCPUAdd -> tmp -> fluid::GClone -> fluid::BGR2Gray -> out // ^ // | //in1 --------` cv::Mat in_mat1(300, 300, CV_8UC3), in_mat2(300, 300, CV_8UC3), out_mat; auto pkg = cv::gapi::kernels(); EXPECT_ANY_THROW(cv::GComputation(cv::GIn(in[0], in[1]), cv::GOut(out)). apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat), cv::compile_args(cv::gapi::use_only{pkg}))); } TEST_F(HeteroGraph, Use_Only_Not_Found_Custom) { //in0 -> cpu::GAdd -> tmp -> fluid::GClone -> fluid::BGR2Gray -> out // ^ // | //in1 --------` cv::Mat in_mat1(300, 300, CV_8UC3), in_mat2(300, 300, CV_8UC3), out_mat; auto pkg = cv::gapi::kernels(); EXPECT_ANY_THROW(cv::GComputation(cv::GIn(in[0], in[1]), cv::GOut(out)). apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat), cv::compile_args(cv::gapi::use_only{pkg}))); } TEST_F(HeteroGraph, Use_Only_Other_Package_Ignored) { //in0 -> cpu::GAdd -> tmp -> fluid::GClone -> fluid::BGR2Gray -> out // ^ // | //in1 --------` cv::Mat in_mat1(300, 300, CV_8UC3), in_mat2(300, 300, CV_8UC3), out_mat; auto pkg = cv::gapi::kernels(); auto clone_pkg = cv::gapi::kernels(); EXPECT_ANY_THROW(cv::GComputation(cv::GIn(in[0], in[1]), cv::GOut(out)). apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat), cv::compile_args(clone_pkg, cv::gapi::use_only{pkg}))); } } // namespace opencv_test