mirror of
https://github.com/opencv/opencv.git
synced 2025-06-11 20:09:23 +08:00
Merge pull request #15869 from TolyaTalamanov:at/plaidml-backend
G-API: Implement PlaidML2 backend * PlaidML backend init version * Add test * Support multiply inputs/outputs in PlaidML2 backend * Fix comment to review * Add HAVE_PLAIDML macros * Move plaidml tests to separate file * Fix comment to review * Fix cmake warning * Fix comments to review * Fix typos overload -> overflow * Fix comments to review * Clean up * Remove spaces from cmake scripts * Disable tests with bitwise operations * Use plaidml::exec::Binder
This commit is contained in:
parent
fb5e7964b3
commit
a7acb8805f
@ -37,6 +37,7 @@ file(GLOB gapi_ext_hdrs
|
||||
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/own/*.hpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/render/*.hpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/streaming/*.hpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/plaidml/*.hpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/util/*.hpp"
|
||||
)
|
||||
|
||||
@ -109,6 +110,10 @@ set(gapi_srcs
|
||||
src/backends/render/grenderocvbackend.cpp
|
||||
src/backends/render/grenderocv.cpp
|
||||
|
||||
#PlaidML Backend
|
||||
src/backends/plaidml/gplaidmlcore.cpp
|
||||
src/backends/plaidml/gplaidmlbackend.cpp
|
||||
|
||||
# Compound
|
||||
src/backends/common/gcompoundbackend.cpp
|
||||
src/backends/common/gcompoundkernel.cpp
|
||||
@ -138,5 +143,12 @@ if(TARGET opencv_test_gapi)
|
||||
target_link_libraries(opencv_test_gapi PRIVATE ade)
|
||||
endif()
|
||||
|
||||
if(HAVE_PLAIDML)
|
||||
ocv_target_compile_definitions(opencv_gapi PRIVATE -DHAVE_PLAIDML)
|
||||
ocv_target_compile_definitions(opencv_test_gapi PRIVATE -DHAVE_PLAIDML)
|
||||
ocv_target_link_libraries(opencv_gapi LINK_PRIVATE ${PLAIDML_LIBRARIES})
|
||||
ocv_target_include_directories(opencv_gapi SYSTEM PRIVATE ${PLAIDML_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
ocv_add_perf_tests()
|
||||
ocv_add_samples()
|
||||
|
@ -1,10 +1,11 @@
|
||||
OCV_OPTION(WITH_ADE "Enable ADE framework (required for Graph API module)" ON)
|
||||
OCV_OPTION(WITH_PLAIDML "Include PlaidML2 support" OFF)
|
||||
|
||||
if(NOT WITH_ADE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if (ade_DIR)
|
||||
if(ade_DIR)
|
||||
# if ade_DIR is set, use ADE-supplied CMake script
|
||||
# to set up variables to the prebuilt ADE
|
||||
find_package(ade 0.1.0)
|
||||
@ -15,3 +16,10 @@ if(NOT TARGET ade)
|
||||
# downloaded one (if there any)
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/DownloadADE.cmake")
|
||||
endif()
|
||||
|
||||
if(WITH_PLAIDML)
|
||||
find_package(PlaidML2 CONFIG QUIET)
|
||||
if (PLAIDML_FOUND)
|
||||
set(HAVE_PLAIDML TRUE)
|
||||
endif()
|
||||
endif()
|
||||
|
20
modules/gapi/include/opencv2/gapi/plaidml/core.hpp
Normal file
20
modules/gapi/include/opencv2/gapi/plaidml/core.hpp
Normal file
@ -0,0 +1,20 @@
|
||||
// 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) 2019 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_PLAIDML_CORE_HPP
|
||||
#define OPENCV_GAPI_PLAIDML_CORE_HPP
|
||||
|
||||
#include <opencv2/gapi/gkernel.hpp> // GKernelPackage
|
||||
#include <opencv2/gapi/own/exports.hpp> // GAPI_EXPORTS
|
||||
|
||||
namespace cv { namespace gapi { namespace core { namespace plaidml {
|
||||
|
||||
GAPI_EXPORTS GKernelPackage kernels();
|
||||
|
||||
}}}}
|
||||
|
||||
#endif // OPENCV_GAPI_PLAIDML_CORE_HPP
|
140
modules/gapi/include/opencv2/gapi/plaidml/gplaidmlkernel.hpp
Normal file
140
modules/gapi/include/opencv2/gapi/plaidml/gplaidmlkernel.hpp
Normal file
@ -0,0 +1,140 @@
|
||||
// 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) 2019 Intel Corporation
|
||||
//
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_GPLAIDMLKERNEL_HPP
|
||||
#define OPENCV_GAPI_GPLAIDMLKERNEL_HPP
|
||||
|
||||
#include <opencv2/gapi/gkernel.hpp>
|
||||
#include <opencv2/gapi/garg.hpp>
|
||||
|
||||
namespace plaidml
|
||||
{
|
||||
namespace edsl
|
||||
{
|
||||
class Tensor;
|
||||
} // namespace edsl
|
||||
} // namespace plaidml
|
||||
|
||||
namespace cv
|
||||
{
|
||||
namespace gapi
|
||||
{
|
||||
namespace plaidml
|
||||
{
|
||||
|
||||
GAPI_EXPORTS cv::gapi::GBackend backend();
|
||||
|
||||
} // namespace plaidml
|
||||
} // namespace gapi
|
||||
|
||||
struct GPlaidMLContext
|
||||
{
|
||||
// Generic accessor API
|
||||
template<typename T>
|
||||
const T& inArg(int input) { return m_args.at(input).get<T>(); }
|
||||
|
||||
// Syntax sugar
|
||||
const plaidml::edsl::Tensor& inTensor(int input)
|
||||
{
|
||||
return inArg<plaidml::edsl::Tensor>(input);
|
||||
}
|
||||
|
||||
plaidml::edsl::Tensor& outTensor(int output)
|
||||
{
|
||||
return *(m_results.at(output).get<plaidml::edsl::Tensor*>());
|
||||
}
|
||||
|
||||
std::vector<GArg> m_args;
|
||||
std::unordered_map<std::size_t, GArg> m_results;
|
||||
};
|
||||
|
||||
class GAPI_EXPORTS GPlaidMLKernel
|
||||
{
|
||||
public:
|
||||
using F = std::function<void(GPlaidMLContext &)>;
|
||||
|
||||
GPlaidMLKernel() = default;
|
||||
explicit GPlaidMLKernel(const F& f) : m_f(f) {};
|
||||
|
||||
void apply(GPlaidMLContext &ctx) const
|
||||
{
|
||||
GAPI_Assert(m_f);
|
||||
m_f(ctx);
|
||||
}
|
||||
|
||||
protected:
|
||||
F m_f;
|
||||
};
|
||||
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<class T> struct plaidml_get_in;
|
||||
template<> struct plaidml_get_in<cv::GMat>
|
||||
{
|
||||
static const plaidml::edsl::Tensor& get(GPlaidMLContext& ctx, int idx)
|
||||
{
|
||||
return ctx.inTensor(idx);
|
||||
}
|
||||
};
|
||||
|
||||
template<class T> struct plaidml_get_in
|
||||
{
|
||||
static T get(GPlaidMLContext &ctx, int idx) { return ctx.inArg<T>(idx); }
|
||||
};
|
||||
|
||||
template<class T> struct plaidml_get_out;
|
||||
template<> struct plaidml_get_out<cv::GMat>
|
||||
{
|
||||
static plaidml::edsl::Tensor& get(GPlaidMLContext& ctx, int idx)
|
||||
{
|
||||
return ctx.outTensor(idx);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename, typename, typename>
|
||||
struct PlaidMLCallHelper;
|
||||
|
||||
template<typename Impl, typename... Ins, typename... Outs>
|
||||
struct PlaidMLCallHelper<Impl, std::tuple<Ins...>, std::tuple<Outs...> >
|
||||
{
|
||||
template<int... IIs, int... OIs>
|
||||
static void call_impl(GPlaidMLContext &ctx, detail::Seq<IIs...>, detail::Seq<OIs...>)
|
||||
{
|
||||
Impl::run(plaidml_get_in<Ins>::get(ctx, IIs)..., plaidml_get_out<Outs>::get(ctx, OIs)...);
|
||||
}
|
||||
|
||||
static void call(GPlaidMLContext& ctx)
|
||||
{
|
||||
call_impl(ctx,
|
||||
typename detail::MkSeq<sizeof...(Ins)>::type(),
|
||||
typename detail::MkSeq<sizeof...(Outs)>::type());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<class Impl, class K>
|
||||
class GPlaidMLKernelImpl: public cv::detail::PlaidMLCallHelper<Impl, typename K::InArgs, typename K::OutArgs>,
|
||||
public cv::detail::KernelTag
|
||||
{
|
||||
using P = detail::PlaidMLCallHelper<Impl, typename K::InArgs, typename K::OutArgs>;
|
||||
|
||||
public:
|
||||
using API = K;
|
||||
|
||||
static cv::gapi::GBackend backend() { return cv::gapi::plaidml::backend(); }
|
||||
static cv::GPlaidMLKernel kernel() { return GPlaidMLKernel(&P::call); }
|
||||
};
|
||||
|
||||
#define GAPI_PLAIDML_KERNEL(Name, API) struct Name: public cv::GPlaidMLKernelImpl<Name, API>
|
||||
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_GPLAIDMLKERNEL_HPP
|
40
modules/gapi/include/opencv2/gapi/plaidml/plaidml.hpp
Normal file
40
modules/gapi/include/opencv2/gapi/plaidml/plaidml.hpp
Normal file
@ -0,0 +1,40 @@
|
||||
// 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) 2019 Intel Corporation
|
||||
|
||||
|
||||
#ifndef OPENCV_GAPI_PLAIDML_PLAIDML_HPP
|
||||
#define OPENCV_GAPI_PLAIDML_PLAIDML_HPP
|
||||
|
||||
#include <string>
|
||||
#include <opencv2/gapi/gcommon.hpp> // CompileArgTag
|
||||
|
||||
namespace cv
|
||||
{
|
||||
namespace gapi
|
||||
{
|
||||
namespace plaidml
|
||||
{
|
||||
|
||||
struct config
|
||||
{
|
||||
std::string dev_id;
|
||||
std::string trg_id;
|
||||
};
|
||||
|
||||
} // namespace plaidml
|
||||
} // namespace gapi
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template<> struct CompileArgTag<cv::gapi::plaidml::config>
|
||||
{
|
||||
static const char* tag() { return "gapi.plaidml.config"; }
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
} // namespace cv
|
||||
|
||||
#endif // OPENCV_GAPI_PLAIDML_PLAIDML_HPP
|
@ -40,6 +40,16 @@ cv::gapi::GBackend::Priv::compile(const ade::Graph&,
|
||||
return {};
|
||||
}
|
||||
|
||||
std::unique_ptr<cv::gimpl::GIslandExecutable>
|
||||
cv::gapi::GBackend::Priv::compile(const ade::Graph& graph,
|
||||
const GCompileArgs& args,
|
||||
const std::vector<ade::NodeHandle>& nodes,
|
||||
const std::vector<cv::gimpl::Data>&,
|
||||
const std::vector<cv::gimpl::Data>&) const
|
||||
{
|
||||
return compile(graph, args, nodes);
|
||||
}
|
||||
|
||||
void cv::gapi::GBackend::Priv::addBackendPasses(ade::ExecutionEngineSetupContext &)
|
||||
{
|
||||
// Do nothing by default, plugins may override this to
|
||||
|
@ -18,6 +18,9 @@
|
||||
#include "opencv2/gapi/gcommon.hpp"
|
||||
#include "opencv2/gapi/gkernel.hpp"
|
||||
|
||||
#include "compiler/gmodel.hpp"
|
||||
|
||||
|
||||
namespace cv
|
||||
{
|
||||
namespace gimpl
|
||||
@ -41,10 +44,18 @@ public:
|
||||
// there's no need in having both cv::gimpl::GBackend
|
||||
// and cv::gapi::GBackend - these two things can be unified
|
||||
// NOTE - nodes are guaranteed to be topologically sorted.
|
||||
|
||||
// NB: This method is deprecated
|
||||
virtual EPtr compile(const ade::Graph &graph,
|
||||
const GCompileArgs &args,
|
||||
const std::vector<ade::NodeHandle> &nodes) const;
|
||||
|
||||
virtual EPtr compile(const ade::Graph &graph,
|
||||
const GCompileArgs &args,
|
||||
const std::vector<ade::NodeHandle> &nodes,
|
||||
const std::vector<cv::gimpl::Data>& ins_data,
|
||||
const std::vector<cv::gimpl::Data>& outs_data) const;
|
||||
|
||||
virtual void addBackendPasses(ade::ExecutionEngineSetupContext &);
|
||||
|
||||
virtual cv::gapi::GKernelPackage auxiliaryKernels() const;
|
||||
|
305
modules/gapi/src/backends/plaidml/gplaidmlbackend.cpp
Normal file
305
modules/gapi/src/backends/plaidml/gplaidmlbackend.cpp
Normal file
@ -0,0 +1,305 @@
|
||||
// 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) 2019 Intel Corporation
|
||||
|
||||
|
||||
#ifdef HAVE_PLAIDML
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
#include <ade/util/algorithm.hpp>
|
||||
#include <ade/util/range.hpp>
|
||||
#include <ade/util/zip_range.hpp>
|
||||
#include <ade/typed_graph.hpp>
|
||||
|
||||
#include <opencv2/gapi/gcommon.hpp>
|
||||
#include <opencv2/gapi/util/any.hpp>
|
||||
#include <opencv2/gapi/gtype_traits.hpp>
|
||||
#include <opencv2/gapi/plaidml/plaidml.hpp>
|
||||
|
||||
#include "compiler/gobjref.hpp"
|
||||
#include "compiler/gmodel.hpp"
|
||||
|
||||
#include "backends/plaidml/gplaidmlbackend.hpp"
|
||||
#include "backends/plaidml/plaidml_util.hpp"
|
||||
|
||||
#include "api/gbackend_priv.hpp" // FIXME: Make it part of Backend SDK!
|
||||
|
||||
using GPlaidMLModel = ade::TypedGraph
|
||||
< cv::gimpl::PlaidMLUnit
|
||||
, cv::gimpl::Protocol
|
||||
>;
|
||||
|
||||
// FIXME: Same issue with Typed and ConstTyped
|
||||
using GConstGPlaidMLModel = ade::ConstTypedGraph
|
||||
< cv::gimpl::PlaidMLUnit
|
||||
, cv::gimpl::Protocol
|
||||
>;
|
||||
|
||||
namespace
|
||||
{
|
||||
class GPlaidMLBackendImpl final: public cv::gapi::GBackend::Priv
|
||||
{
|
||||
virtual void unpackKernel(ade::Graph &graph,
|
||||
const ade::NodeHandle &op_node,
|
||||
const cv::GKernelImpl &impl) override
|
||||
{
|
||||
GPlaidMLModel gm(graph);
|
||||
auto plaidml_impl = cv::util::any_cast<cv::GPlaidMLKernel>(impl.opaque);
|
||||
gm.metadata(op_node).set(cv::gimpl::PlaidMLUnit{plaidml_impl});
|
||||
}
|
||||
|
||||
virtual EPtr compile(const ade::Graph& graph,
|
||||
const cv::GCompileArgs& args,
|
||||
const std::vector<ade::NodeHandle>& nodes,
|
||||
const std::vector<cv::gimpl::Data>& ins_data,
|
||||
const std::vector<cv::gimpl::Data>& outs_data) const override
|
||||
{
|
||||
auto has_config = cv::gimpl::getCompileArg<cv::gapi::plaidml::config>(args);
|
||||
|
||||
if (!has_config)
|
||||
{
|
||||
cv::util::throw_error(std::runtime_error("Config not found!\n"
|
||||
"You must pass cv::gapi::plaidml::config to the graph compile arguments"));
|
||||
}
|
||||
|
||||
const auto& arg = has_config.value();
|
||||
return EPtr{new cv::gimpl::GPlaidMLExecutable(cv::gimpl::GPlaidMLExecutable::Config{arg.dev_id, arg.trg_id},
|
||||
graph, nodes, ins_data, outs_data)};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
cv::gapi::GBackend cv::gapi::plaidml::backend()
|
||||
{
|
||||
static cv::gapi::GBackend this_backend(std::make_shared<GPlaidMLBackendImpl>());
|
||||
return this_backend;
|
||||
}
|
||||
|
||||
void cv::gimpl::GPlaidMLExecutable::initBuffers(const std::vector<cv::gimpl::Data>& data,
|
||||
std::vector<plaidml::exec::Binding>& bindings)
|
||||
{
|
||||
|
||||
// NB: This is necessary because we keep a pointer to bindings elements to buffer_map
|
||||
// In order to them to remain valid it's required to prevant reallocation
|
||||
bindings.reserve(data.size());
|
||||
for (const auto& d : data)
|
||||
{
|
||||
GAPI_Assert(d.shape == GShape::GMAT &&
|
||||
"Now PlaidML backend supports only cv::GMat's");
|
||||
|
||||
const auto& desc = cv::util::get<cv::GMatDesc>(d.meta);
|
||||
|
||||
auto placeholder = plaidml::edsl::Placeholder(
|
||||
cv::util::plaidml::depth_from_ocv(desc.depth),
|
||||
{desc.size.width, desc.size.height, desc.chan});
|
||||
|
||||
const auto& shape = placeholder.shape();
|
||||
plaidml::TensorShape tshape(shape.dtype(), shape.int_dims());
|
||||
plaidml::Buffer buffer(m_cfg.dev_id, tshape);
|
||||
|
||||
bindings.push_back(plaidml::exec::Binding{std::move(placeholder),
|
||||
std::move(buffer)});
|
||||
|
||||
auto& tensor_map = m_res.slot<plaidml::edsl::Tensor>();
|
||||
// FIXME Avoid Copy here !!!
|
||||
tensor_map.emplace(d.rc, bindings.back().tensor);
|
||||
|
||||
auto& buffer_map = m_res.slot<plaidml::Buffer*>();
|
||||
buffer_map.emplace(d.rc, &(bindings.back().buffer));
|
||||
}
|
||||
}
|
||||
|
||||
void cv::gimpl::GPlaidMLExecutable::compile(const std::vector<cv::gimpl::Data>& ins_data,
|
||||
const std::vector<cv::gimpl::Data>& outs_data)
|
||||
{
|
||||
initBuffers(ins_data, input_bindings_);
|
||||
initBuffers(outs_data, output_bindings_);
|
||||
|
||||
ade::util::transform(outs_data, std::back_inserter(output_ids_),
|
||||
[](const cv::gimpl::Data& d) { return d.rc; });
|
||||
|
||||
GConstGPlaidMLModel gcm(m_g);
|
||||
for (const auto& nh : m_all_ops)
|
||||
{
|
||||
const auto& k = gcm.metadata(nh).get<PlaidMLUnit>().k;
|
||||
GPlaidMLContext ctx;
|
||||
|
||||
const auto &op = m_gm.metadata(nh).get<Op>();
|
||||
ctx.m_args.reserve(op.args.size());
|
||||
|
||||
using namespace std::placeholders;
|
||||
ade::util::transform(op.args,
|
||||
std::back_inserter(ctx.m_args),
|
||||
std::bind(&GPlaidMLExecutable::packArg, this, _1));
|
||||
|
||||
for (const auto &out_it : ade::util::indexed(op.outs))
|
||||
{
|
||||
const auto out_port = ade::util::index(out_it);
|
||||
const auto out_desc = ade::util::value(out_it);
|
||||
|
||||
auto& tensor_map = m_res.slot<plaidml::edsl::Tensor>();
|
||||
|
||||
// NB: Create tensor if need
|
||||
auto& tensor = tensor_map[out_desc.id];
|
||||
ctx.m_results[out_port] = GArg(&(tensor));
|
||||
}
|
||||
|
||||
k.apply(ctx);
|
||||
}
|
||||
|
||||
std::vector<plaidml::edsl::Tensor> output_tensors;
|
||||
for (const auto& out_id : output_ids_)
|
||||
{
|
||||
auto& tensor_map = m_res.slot<plaidml::edsl::Tensor>();
|
||||
// FIXME Avoid copy here !!!
|
||||
output_tensors.emplace_back(tensor_map[out_id]);
|
||||
}
|
||||
|
||||
plaidml::edsl::Program program("Program", output_tensors);
|
||||
binder_.reset(new plaidml::exec::Binder(program));
|
||||
|
||||
for (const auto& binding : input_bindings_)
|
||||
{
|
||||
binder_->set_input(binding.tensor, binding.buffer);
|
||||
}
|
||||
|
||||
for (const auto& binding : output_bindings_)
|
||||
{
|
||||
binder_->set_output(binding.tensor, binding.buffer);
|
||||
}
|
||||
|
||||
exec_ = binder_->compile();
|
||||
}
|
||||
|
||||
cv::gimpl::GPlaidMLExecutable::GPlaidMLExecutable(cv::gimpl::GPlaidMLExecutable::Config cfg,
|
||||
const ade::Graph& g,
|
||||
const std::vector<ade::NodeHandle>& nodes,
|
||||
const std::vector<cv::gimpl::Data>& ins_data,
|
||||
const std::vector<cv::gimpl::Data>& outs_data)
|
||||
: m_cfg(std::move(cfg)), m_g(g), m_gm(m_g)
|
||||
{
|
||||
auto is_op = [&](ade::NodeHandle nh) {
|
||||
return m_gm.metadata(nh).get<NodeType>().t == NodeType::OP;
|
||||
};
|
||||
|
||||
std::copy_if(nodes.begin(), nodes.end(), std::back_inserter(m_all_ops), is_op);
|
||||
|
||||
compile(ins_data, outs_data);
|
||||
}
|
||||
|
||||
void cv::gimpl::GPlaidMLExecutable::run(std::vector<InObj> &&input_objs,
|
||||
std::vector<OutObj> &&output_objs)
|
||||
{
|
||||
for (auto& it : input_objs) bindInArg (it.first, it.second);
|
||||
|
||||
exec_->run();
|
||||
|
||||
for (auto& it : output_objs) bindOutArg(it.first, it.second);
|
||||
}
|
||||
|
||||
void cv::gimpl::GPlaidMLExecutable::bindInArg(const RcDesc &rc, const GRunArg &arg)
|
||||
{
|
||||
switch (rc.shape)
|
||||
{
|
||||
case GShape::GMAT:
|
||||
{
|
||||
auto& tensor_map = m_res.slot<plaidml::edsl::Tensor>();
|
||||
auto it = tensor_map.find(rc.id);
|
||||
GAPI_Assert(it != tensor_map.end());
|
||||
|
||||
switch (arg.index())
|
||||
{
|
||||
case GRunArg::index_of<cv::gapi::own::Mat>():
|
||||
{
|
||||
auto& arg_mat = util::get<cv::gapi::own::Mat>(arg);
|
||||
binder_->input(it->second).copy_from(arg_mat.data);
|
||||
}
|
||||
break;
|
||||
#if !defined(GAPI_STANDALONE)
|
||||
case GRunArg::index_of<cv::Mat>() :
|
||||
{
|
||||
auto& arg_mat = util::get<cv::Mat>(arg);
|
||||
binder_->input(it->second).copy_from(arg_mat.data);
|
||||
}
|
||||
break;
|
||||
#endif // !defined(GAPI_STANDALONE)
|
||||
default: util::throw_error(std::logic_error("content type of the runtime argument does not match to resource description ?"));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
util::throw_error(std::logic_error("Unsupported GShape type"));
|
||||
}
|
||||
}
|
||||
|
||||
void cv::gimpl::GPlaidMLExecutable::bindOutArg(const RcDesc &rc, const GRunArgP &arg)
|
||||
{
|
||||
switch (rc.shape)
|
||||
{
|
||||
case GShape::GMAT:
|
||||
{
|
||||
auto& tensor_map = m_res.slot<plaidml::edsl::Tensor>();
|
||||
auto it = tensor_map.find(rc.id);
|
||||
GAPI_Assert(it != tensor_map.end());
|
||||
|
||||
switch (arg.index())
|
||||
{
|
||||
case GRunArgP::index_of<cv::gapi::own::Mat*>():
|
||||
{
|
||||
auto& arg_mat = *util::get<cv::gapi::own::Mat*>(arg);
|
||||
binder_->output(it->second).copy_into(arg_mat.data);
|
||||
}
|
||||
break;
|
||||
#if !defined(GAPI_STANDALONE)
|
||||
case GRunArgP::index_of<cv::Mat*>() :
|
||||
{
|
||||
auto& arg_mat = *util::get<cv::Mat*>(arg);
|
||||
binder_->output(it->second).copy_into(arg_mat.data);
|
||||
}
|
||||
break;
|
||||
#endif // !defined(GAPI_STANDALONE)
|
||||
default: util::throw_error(std::logic_error("content type of the runtime argument does not match to resource description ?"));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
util::throw_error(std::logic_error("Unsupported GShape type"));
|
||||
}
|
||||
}
|
||||
|
||||
cv::GArg cv::gimpl::GPlaidMLExecutable::packArg(const GArg &arg)
|
||||
{
|
||||
GAPI_Assert( arg.kind != cv::detail::ArgKind::GMAT
|
||||
&& arg.kind != cv::detail::ArgKind::GSCALAR
|
||||
&& arg.kind != cv::detail::ArgKind::GARRAY);
|
||||
|
||||
if (arg.kind != cv::detail::ArgKind::GOBJREF)
|
||||
{
|
||||
// All other cases - pass as-is, with no transformations to GArg contents.
|
||||
return arg;
|
||||
}
|
||||
GAPI_Assert(arg.kind == cv::detail::ArgKind::GOBJREF);
|
||||
|
||||
const cv::gimpl::RcDesc &ref = arg.get<cv::gimpl::RcDesc>();
|
||||
switch (ref.shape)
|
||||
{
|
||||
case GShape::GMAT:
|
||||
{
|
||||
auto& tensor_map = m_res.slot<plaidml::edsl::Tensor>();
|
||||
auto it = tensor_map.find(ref.id);
|
||||
GAPI_Assert(it != tensor_map.end());
|
||||
return GArg(it->second);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
util::throw_error(std::logic_error("Unsupported GShape type"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // HAVE_PLAIDML
|
100
modules/gapi/src/backends/plaidml/gplaidmlbackend.hpp
Normal file
100
modules/gapi/src/backends/plaidml/gplaidmlbackend.hpp
Normal file
@ -0,0 +1,100 @@
|
||||
// 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) 2019 Intel Corporation
|
||||
|
||||
#ifdef HAVE_PLAIDML
|
||||
|
||||
#ifndef OPENCV_GAPI_GPLAIDMLBACKEND_HPP
|
||||
#define OPENCV_GAPI_GPLAIDMLBACKEND_HPP
|
||||
|
||||
#include <map> // map
|
||||
#include <unordered_map> // unordered_map
|
||||
#include <tuple> // tuple
|
||||
#include <ade/util/algorithm.hpp> // type_list_index
|
||||
|
||||
#include <opencv2/gapi/garg.hpp>
|
||||
#include <opencv2/gapi/gproto.hpp>
|
||||
#include <opencv2/gapi/plaidml/gplaidmlkernel.hpp>
|
||||
|
||||
#include "api/gorigin.hpp"
|
||||
#include "backends/common/gbackend.hpp"
|
||||
|
||||
#include "compiler/gislandmodel.hpp"
|
||||
|
||||
#include <plaidml2/exec/exec.h>
|
||||
#include <plaidml2/core/core.h>
|
||||
|
||||
namespace cv { namespace gimpl {
|
||||
|
||||
struct PlaidMLUnit
|
||||
{
|
||||
static const char *name() { return "PlaidMLKernel"; }
|
||||
GPlaidMLKernel k;
|
||||
};
|
||||
|
||||
class GPlaidMLExecutable final: public GIslandExecutable
|
||||
{
|
||||
public:
|
||||
struct Config
|
||||
{
|
||||
std::string dev_id;
|
||||
std::string trg_id;
|
||||
};
|
||||
|
||||
GPlaidMLExecutable(Config cfg,
|
||||
const ade::Graph& graph,
|
||||
const std::vector<ade::NodeHandle>& nodes,
|
||||
const std::vector<cv::gimpl::Data>& ins_data,
|
||||
const std::vector<cv::gimpl::Data>& outs_data);
|
||||
|
||||
virtual inline bool canReshape() const override { return false; }
|
||||
|
||||
virtual inline void reshape(ade::Graph&, const GCompileArgs&) override
|
||||
{
|
||||
util::throw_error(std::logic_error("GPlaidMLExecutable::reshape() should never be called"));
|
||||
}
|
||||
|
||||
virtual void run(std::vector<InObj> &&input_objs,
|
||||
std::vector<OutObj> &&output_objs) override;
|
||||
|
||||
private:
|
||||
void initBuffers(const std::vector<cv::gimpl::Data>& ins_data,
|
||||
std::vector<plaidml::exec::Binding>& bindings);
|
||||
|
||||
void bindInArg (const RcDesc &rc, const GRunArg &arg);
|
||||
void bindOutArg (const RcDesc &rc, const GRunArgP &arg);
|
||||
|
||||
void compile(const std::vector<cv::gimpl::Data>& ins_data,
|
||||
const std::vector<cv::gimpl::Data>& outs_data);
|
||||
|
||||
// FIXME User also can pass config via compile args ?
|
||||
void initConfig();
|
||||
|
||||
GArg packArg(const GArg &arg);
|
||||
|
||||
Config m_cfg;
|
||||
|
||||
const ade::Graph &m_g;
|
||||
GModel::ConstGraph m_gm;
|
||||
|
||||
std::vector<ade::NodeHandle> m_all_ops;
|
||||
|
||||
std::vector<size_t> output_ids_;
|
||||
|
||||
std::unique_ptr<plaidml::exec::Binder> binder_;
|
||||
std::shared_ptr<plaidml::exec::Executable> exec_;
|
||||
|
||||
std::vector<plaidml::exec::Binding> input_bindings_;
|
||||
std::vector<plaidml::exec::Binding> output_bindings_;
|
||||
|
||||
using Mag = detail::magazine<plaidml::edsl::Tensor, plaidml::Buffer*>;
|
||||
Mag m_res;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif // OPENCV_GAPI_GPLAIDMLBACKEND_HPP
|
||||
|
||||
#endif // HAVE_PLAIDML
|
54
modules/gapi/src/backends/plaidml/gplaidmlcore.cpp
Normal file
54
modules/gapi/src/backends/plaidml/gplaidmlcore.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
// 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) 2019 Intel Corporation
|
||||
|
||||
|
||||
#ifdef HAVE_PLAIDML
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
#include <opencv2/gapi/core.hpp>
|
||||
#include <opencv2/gapi/plaidml/core.hpp>
|
||||
#include <opencv2/gapi/plaidml/gplaidmlkernel.hpp>
|
||||
|
||||
#include <plaidml2/edsl/edsl.h>
|
||||
|
||||
#define GAPI_PLAIDML_LOGICAL_OP(Name, API, Op) \
|
||||
GAPI_PLAIDML_KERNEL(Name, API) \
|
||||
{ \
|
||||
static void run(const plaidml::edsl::Tensor& src1, \
|
||||
const plaidml::edsl::Tensor& src2, \
|
||||
plaidml::edsl::Tensor& dst) \
|
||||
{ \
|
||||
dst = src1 Op src2; \
|
||||
}; \
|
||||
}; \
|
||||
|
||||
#define GAPI_PLAIDML_ARITHMETIC_OP(Name, API, Op) \
|
||||
GAPI_PLAIDML_KERNEL(Name, API) \
|
||||
{ \
|
||||
static void run(const plaidml::edsl::Tensor& src1, \
|
||||
const plaidml::edsl::Tensor& src2, \
|
||||
int, /* dtype */ \
|
||||
plaidml::edsl::Tensor& dst) \
|
||||
{ \
|
||||
dst = src1 Op src2; \
|
||||
}; \
|
||||
}; \
|
||||
|
||||
GAPI_PLAIDML_LOGICAL_OP(GPlaidMLAnd, cv::gapi::core::GAnd, &);
|
||||
GAPI_PLAIDML_LOGICAL_OP(GPlaidMLXor, cv::gapi::core::GXor, ^);
|
||||
GAPI_PLAIDML_LOGICAL_OP(GPlaidMLOr , cv::gapi::core::GOr , |)
|
||||
|
||||
GAPI_PLAIDML_ARITHMETIC_OP(GPlaidMLAdd, cv::gapi::core::GAdd, +);
|
||||
GAPI_PLAIDML_ARITHMETIC_OP(GPlaidMLSub, cv::gapi::core::GSub, -);
|
||||
|
||||
cv::gapi::GKernelPackage cv::gapi::core::plaidml::kernels()
|
||||
{
|
||||
static auto pkg = cv::gapi::kernels<GPlaidMLAdd, GPlaidMLSub, GPlaidMLAnd, GPlaidMLXor, GPlaidMLOr>();
|
||||
return pkg;
|
||||
}
|
||||
|
||||
#endif // HACE_PLAIDML
|
42
modules/gapi/src/backends/plaidml/plaidml_util.hpp
Normal file
42
modules/gapi/src/backends/plaidml/plaidml_util.hpp
Normal file
@ -0,0 +1,42 @@
|
||||
// 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) 2019 Intel Corporation
|
||||
|
||||
|
||||
#ifdef HAVE_PLAIDML
|
||||
|
||||
#ifndef OPENCV_GAPI_PLAIDML_UTIL_HPP
|
||||
#define OPENCV_GAPI_PLAIDML_UTIL_HPP
|
||||
|
||||
#include <plaidml2/core/ffi.h>
|
||||
|
||||
namespace cv
|
||||
{
|
||||
namespace util
|
||||
{
|
||||
namespace plaidml
|
||||
{
|
||||
|
||||
inline plaidml_datatype depth_from_ocv(int depth)
|
||||
{
|
||||
switch(depth)
|
||||
{
|
||||
case CV_8U : return PLAIDML_DATA_UINT8;
|
||||
case CV_8S : return PLAIDML_DATA_INT8;
|
||||
case CV_16U : return PLAIDML_DATA_UINT16;
|
||||
case CV_16S : return PLAIDML_DATA_INT16;
|
||||
case CV_32S : return PLAIDML_DATA_INT32;
|
||||
case CV_32F : return PLAIDML_DATA_FLOAT32;
|
||||
case CV_64F : return PLAIDML_DATA_FLOAT64;
|
||||
default: util::throw_error("Unrecognized OpenCV depth");
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // OPENCV_GAPI_PLAIDML_UTIL_HPP
|
||||
|
||||
#endif // HAVE_PLAIDML
|
@ -16,6 +16,8 @@
|
||||
#include "api/gbackend_priv.hpp" // GBackend::Priv().compile()
|
||||
#include "compiler/gmodel.hpp"
|
||||
#include "compiler/gislandmodel.hpp"
|
||||
#include "compiler/gmodel.hpp"
|
||||
|
||||
#include "logger.hpp" // GAPI_LOG
|
||||
|
||||
namespace cv { namespace gimpl {
|
||||
@ -257,6 +259,20 @@ void GIslandModel::compileIslands(Graph &g, const ade::Graph &orig_g, const GCom
|
||||
{
|
||||
if (NodeKind::ISLAND == g.metadata(nh).get<NodeKind>().k)
|
||||
{
|
||||
auto nodes_to_data = [&](const ade::NodeHandle& dnh)
|
||||
{
|
||||
GAPI_Assert(g.metadata(dnh).get<NodeKind>().k == NodeKind::SLOT);
|
||||
const auto& orig_data_nh = g.metadata(dnh).get<DataSlot>().original_data_node;
|
||||
const auto& data = gm.metadata(orig_data_nh).get<Data>();
|
||||
return data;
|
||||
};
|
||||
|
||||
std::vector<cv::gimpl::Data> ins_data;
|
||||
ade::util::transform(nh->inNodes(), std::back_inserter(ins_data), nodes_to_data);
|
||||
|
||||
std::vector<cv::gimpl::Data> outs_data;
|
||||
ade::util::transform(nh->outNodes(), std::back_inserter(outs_data), nodes_to_data);
|
||||
|
||||
auto island_obj = g.metadata(nh).get<FusedIsland>().object;
|
||||
auto island_ops = island_obj->contents();
|
||||
|
||||
@ -268,8 +284,9 @@ void GIslandModel::compileIslands(Graph &g, const ade::Graph &orig_g, const GCom
|
||||
});
|
||||
|
||||
auto island_exe = island_obj->backend().priv()
|
||||
.compile(orig_g, args, topo_sorted_list);
|
||||
.compile(orig_g, args, topo_sorted_list, ins_data, outs_data);
|
||||
GAPI_Assert(nullptr != island_exe);
|
||||
|
||||
g.metadata(nh).set(IslandExec{std::move(island_exe)});
|
||||
}
|
||||
}
|
||||
|
@ -96,6 +96,7 @@ protected:
|
||||
// * Is instantiated by the last step of the Islands fusion procedure;
|
||||
// * Is orchestrated by a GExecutor instance.
|
||||
//
|
||||
|
||||
class GIslandExecutable
|
||||
{
|
||||
public:
|
||||
|
@ -62,7 +62,8 @@ cv::gimpl::GExecutor::GExecutor(std::unique_ptr<ade::Graph> &&g_model)
|
||||
|
||||
m_ops.emplace_back(OpDesc{ std::move(input_rcs)
|
||||
, std::move(output_rcs)
|
||||
, m_gim.metadata(nh).get<IslandExec>().object});
|
||||
, m_gim.metadata(nh).get<IslandExec>().object
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
|
178
modules/gapi/test/gapi_plaidml_pipelines.cpp
Normal file
178
modules/gapi/test/gapi_plaidml_pipelines.cpp
Normal file
@ -0,0 +1,178 @@
|
||||
// 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) 2019 Intel Corporation
|
||||
|
||||
|
||||
#ifdef HAVE_PLAIDML
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <ade/util/iota_range.hpp>
|
||||
#include "logger.hpp"
|
||||
|
||||
#include <opencv2/gapi/plaidml/core.hpp>
|
||||
#include <opencv2/gapi/plaidml/plaidml.hpp>
|
||||
|
||||
namespace opencv_test
|
||||
{
|
||||
|
||||
inline cv::gapi::plaidml::config getConfig()
|
||||
{
|
||||
auto read_var_from_env = [](const char* env)
|
||||
{
|
||||
const char* raw = std::getenv(env);
|
||||
if (!raw)
|
||||
{
|
||||
cv::util::throw_error(std::runtime_error(std::string(env) + " is't set"));
|
||||
}
|
||||
|
||||
return std::string(raw);
|
||||
};
|
||||
|
||||
auto dev_id = read_var_from_env("PLAIDML_DEVICE");
|
||||
auto trg_id = read_var_from_env("PLAIDML_TARGET");
|
||||
|
||||
return cv::gapi::plaidml::config{std::move(dev_id),
|
||||
std::move(trg_id)};
|
||||
}
|
||||
|
||||
TEST(GAPI_PlaidML_Pipelines, SimpleArithmetic)
|
||||
{
|
||||
cv::Size size(1920, 1080);
|
||||
int type = CV_8UC1;
|
||||
|
||||
cv::Mat in_mat1(size, type);
|
||||
cv::Mat in_mat2(size, type);
|
||||
|
||||
// NB: What about overflow ? PlaidML doesn't handle it
|
||||
cv::randu(in_mat1, cv::Scalar::all(0), cv::Scalar::all(127));
|
||||
cv::randu(in_mat2, cv::Scalar::all(0), cv::Scalar::all(127));
|
||||
|
||||
cv::Mat out_mat(size, type, cv::Scalar::all(0));
|
||||
cv::Mat ref_mat(size, type, cv::Scalar::all(0));
|
||||
|
||||
////////////////////////////// G-API //////////////////////////////////////
|
||||
cv::GMat in1, in2;
|
||||
auto out = in1 + in2;
|
||||
|
||||
cv::GComputation comp(cv::GIn(in1, in2), cv::GOut(out));
|
||||
comp.apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat),
|
||||
cv::compile_args(getConfig(),
|
||||
cv::gapi::use_only{cv::gapi::core::plaidml::kernels()}));
|
||||
|
||||
////////////////////////////// OpenCV /////////////////////////////////////
|
||||
cv::add(in_mat1, in_mat2, ref_mat, cv::noArray(), type);
|
||||
|
||||
EXPECT_EQ(0, cv::norm(out_mat, ref_mat));
|
||||
}
|
||||
|
||||
// FIXME PlaidML cpu backend does't support bitwise operations
|
||||
TEST(GAPI_PlaidML_Pipelines, DISABLED_ComplexArithmetic)
|
||||
{
|
||||
cv::Size size(1920, 1080);
|
||||
int type = CV_8UC1;
|
||||
|
||||
cv::Mat in_mat1(size, type);
|
||||
cv::Mat in_mat2(size, type);
|
||||
|
||||
cv::randu(in_mat1, cv::Scalar::all(0), cv::Scalar::all(255));
|
||||
cv::randu(in_mat2, cv::Scalar::all(0), cv::Scalar::all(255));
|
||||
|
||||
cv::Mat out_mat(size, type, cv::Scalar::all(0));
|
||||
cv::Mat ref_mat(size, type, cv::Scalar::all(0));
|
||||
|
||||
////////////////////////////// G-API //////////////////////////////////////
|
||||
cv::GMat in1, in2;
|
||||
auto out = in1 | (in2 ^ (in1 & (in2 + (in1 - in2))));
|
||||
|
||||
cv::GComputation comp(cv::GIn(in1, in2), cv::GOut(out));
|
||||
comp.apply(cv::gin(in_mat1, in_mat2), cv::gout(out_mat),
|
||||
cv::compile_args(getConfig(),
|
||||
cv::gapi::use_only{cv::gapi::core::plaidml::kernels()}));
|
||||
|
||||
////////////////////////////// OpenCV /////////////////////////////////////
|
||||
cv::subtract(in_mat1, in_mat2, ref_mat, cv::noArray(), type);
|
||||
cv::add(in_mat2, ref_mat, ref_mat, cv::noArray(), type);
|
||||
cv::bitwise_and(in_mat1, ref_mat, ref_mat);
|
||||
cv::bitwise_xor(in_mat2, ref_mat, ref_mat);
|
||||
cv::bitwise_or(in_mat1, ref_mat, ref_mat);
|
||||
|
||||
EXPECT_EQ(0, cv::norm(out_mat, ref_mat));
|
||||
}
|
||||
|
||||
TEST(GAPI_PlaidML_Pipelines, TwoInputOperations)
|
||||
{
|
||||
cv::Size size(1920, 1080);
|
||||
int type = CV_8UC1;
|
||||
|
||||
constexpr int kNumInputs = 4;
|
||||
std::vector<cv::Mat> in_mat(kNumInputs, cv::Mat(size, type));
|
||||
for (int i = 0; i < kNumInputs; ++i)
|
||||
{
|
||||
cv::randu(in_mat[i], cv::Scalar::all(0), cv::Scalar::all(60));
|
||||
}
|
||||
|
||||
cv::Mat out_mat(size, type, cv::Scalar::all(0));
|
||||
cv::Mat ref_mat(size, type, cv::Scalar::all(0));
|
||||
|
||||
////////////////////////////// G-API //////////////////////////////////////
|
||||
cv::GMat in[4];
|
||||
auto out = (in[3] - in[0]) + (in[2] - in[1]);
|
||||
|
||||
cv::GComputation comp(cv::GIn(in[0], in[1], in[2], in[3]), cv::GOut(out));
|
||||
|
||||
// FIXME Doesn't work just apply(in_mat, out_mat, ...)
|
||||
comp.apply(cv::gin(in_mat[0], in_mat[1], in_mat[2], in_mat[3]), cv::gout(out_mat),
|
||||
cv::compile_args(getConfig(),
|
||||
cv::gapi::use_only{cv::gapi::core::plaidml::kernels()}));
|
||||
|
||||
////////////////////////////// OpenCV /////////////////////////////////////
|
||||
cv::subtract(in_mat[3], in_mat[0], ref_mat, cv::noArray(), type);
|
||||
cv::add(ref_mat, in_mat[2], ref_mat, cv::noArray(), type);
|
||||
cv::subtract(ref_mat, in_mat[1], ref_mat, cv::noArray(), type);
|
||||
|
||||
EXPECT_EQ(0, cv::norm(out_mat, ref_mat));
|
||||
}
|
||||
|
||||
TEST(GAPI_PlaidML_Pipelines, TwoOutputOperations)
|
||||
{
|
||||
cv::Size size(1920, 1080);
|
||||
int type = CV_8UC1;
|
||||
|
||||
constexpr int kNumInputs = 4;
|
||||
std::vector<cv::Mat> in_mat(kNumInputs, cv::Mat(size, type));
|
||||
for (int i = 0; i < kNumInputs; ++i)
|
||||
{
|
||||
cv::randu(in_mat[i], cv::Scalar::all(0), cv::Scalar::all(60));
|
||||
}
|
||||
|
||||
std::vector<cv::Mat> out_mat(kNumInputs, cv::Mat(size, type, cv::Scalar::all(0)));
|
||||
std::vector<cv::Mat> ref_mat(kNumInputs, cv::Mat(size, type, cv::Scalar::all(0)));
|
||||
|
||||
////////////////////////////// G-API //////////////////////////////////////
|
||||
cv::GMat in[4], out[2];
|
||||
out[0] = in[0] + in[3];
|
||||
out[1] = in[1] + in[2];
|
||||
|
||||
cv::GComputation comp(cv::GIn(in[0], in[1], in[2], in[3]), cv::GOut(out[0], out[1]));
|
||||
|
||||
// FIXME Doesn't work just apply(in_mat, out_mat, ...)
|
||||
comp.apply(cv::gin(in_mat[0], in_mat[1], in_mat[2], in_mat[3]),
|
||||
cv::gout(out_mat[0], out_mat[1]),
|
||||
cv::compile_args(getConfig(),
|
||||
cv::gapi::use_only{cv::gapi::core::plaidml::kernels()}));
|
||||
|
||||
////////////////////////////// OpenCV /////////////////////////////////////
|
||||
cv::add(in_mat[0], in_mat[3], ref_mat[0], cv::noArray(), type);
|
||||
cv::add(in_mat[1], in_mat[2], ref_mat[1], cv::noArray(), type);
|
||||
|
||||
EXPECT_EQ(0, cv::norm(out_mat[0], ref_mat[0]));
|
||||
EXPECT_EQ(0, cv::norm(out_mat[1], ref_mat[1]));
|
||||
}
|
||||
|
||||
} // namespace opencv_test
|
||||
|
||||
#endif // HAVE_PLAIDML
|
@ -11,7 +11,8 @@
|
||||
#include <ade/util/iota_range.hpp>
|
||||
#include "logger.hpp"
|
||||
|
||||
#include <opencv2/gapi/render/render.hpp>
|
||||
#include <opencv2/gapi/plaidml/core.hpp>
|
||||
|
||||
|
||||
namespace opencv_test
|
||||
{
|
||||
@ -315,4 +316,5 @@ TEST(GAPI_Pipeline, CanUseOwnMatAsOutput)
|
||||
// FIXME add overload for apply(cv::gapi::own::Mat in, cv::gapi::own::Mat& out)
|
||||
EXPECT_NO_THROW(comp.apply({in_own_mat}, {out_own_mat}));
|
||||
}
|
||||
|
||||
} // namespace opencv_test
|
||||
|
Loading…
Reference in New Issue
Block a user