// 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, all rights reserved. // Third party copyrights are property of their respective owners. #include "precomp.hpp" #include #include "op_vkcom.hpp" #include "net_impl.hpp" namespace cv { namespace dnn { #ifdef HAVE_VULKAN CV__DNN_INLINE_NS_BEGIN void Net::Impl::initVkComBackend() { CV_TRACE_FUNCTION(); CV_Assert(preferableBackend == DNN_BACKEND_VKCOM); context = vkcom::Context::create(); for (MapIdToLayerData::iterator it = layers.begin(); it != layers.end(); it++) { LayerData &ld = it->second; Ptr layer = ld.layerInstance; if (!layer->supportBackend(preferableBackend)) { continue; } try { ld.backendNodes[DNN_BACKEND_VKCOM] = layer->initVkCom(ld.inputBlobsWrappers, ld.outputBlobsWrappers); } catch (const cv::Exception& e) { CV_LOG_ERROR(NULL, "initVkCom failed, fallback to CPU implementation. " << e.what()); ld.backendNodes[DNN_BACKEND_VKCOM] = Ptr(); } } } CV__DNN_INLINE_NS_END /////////////////////////////////////////////////////////////////////////////// int transFusedActivType(Ptr &actLayer) { if (actLayer) { Ptr activ_relu = actLayer.dynamicCast(); Ptr activ_relu6 = actLayer.dynamicCast(); if (!activ_relu.empty()) { if (activ_relu->negativeSlope == 0.0f) { return 1; // kFusedActivRelu } else // Leaky ReLU { return -1; // kFusedActivNone } } else if (!activ_relu6.empty()) { return 2; // kFusedActivRelu6 } else return -1; // kFusedActivUnsupport } else return 0; // kFusedActivNone } void copyToTensor(vkcom::Tensor &dst, const Mat &src) { CV_Assert(src.isContinuous() && src.type() == CV_32F); std::vector mat_shape = shape(src); // The following code will copy the src data from CPU Mat to GPU VkBuffer. dst.reshape((const char*)src.data, mat_shape); } void copyToMat(Mat &dst, vkcom::Tensor &src) { CV_Assert(dst.type() == CV_32F); std::vector shape = src.getShape(); void *data = src.map(); Mat tmp(shape, CV_32F, data); tmp.copyTo(dst); src.unMap(); } vkcom::Tensor VkComTensor(const Ptr& ptr) { CV_Assert(!ptr.empty()); return ptr.dynamicCast()->getTensor(); } void setDirty(std::vector >& ptrs) { for (const Ptr& ptr : ptrs) { ptr.dynamicCast()->setDeviceDirty(); } } std::vector VkComTensors(const std::vector >& ptrs) { std::vector vec; vec.reserve(ptrs.size()); for (const Ptr& ptr : ptrs) { vec.push_back(VkComTensor(ptr)); } return vec; } VkComBackendNode::VkComBackendNode(const std::vector >& inputsWrapper, const Ptr& op, const std::vector >& outputsWrapper) : BackendNode(DNN_BACKEND_VKCOM) { operation = op; inputsWrapper_ = inputsWrapper; ins = VkComTensors(inputsWrapper_); outputsWrapper_ = outputsWrapper; outs = VkComTensors(outputsWrapper_); } bool VkComBackendNode::forward() { for (int i = 0, n = inputsWrapper_.size(); i < n; ++i) { inputsWrapper_[i].dynamicCast()->copyToDevice(); } return operation->forward(ins, outs); } VkComBackendWrapper::VkComBackendWrapper(Mat& m) : BackendWrapper(DNN_BACKEND_VKCOM, DNN_TARGET_VULKAN) { CV_Assert(m.isContinuous()); copyToTensor(tensor, m); host = &m; hostDirty = false; deviceDirty = false; } // Other constructor, need change the logical. The purpose is to decline the data copy. VkComBackendWrapper::VkComBackendWrapper(const Ptr& baseBuffer, Mat& m) : BackendWrapper(DNN_BACKEND_VKCOM, DNN_TARGET_VULKAN) { Ptr base = baseBuffer.dynamicCast(); CV_Assert(!base.empty()); host = &m; tensor = base->tensor; CV_Assert(tensor.count() >= m.total()); tensor.reshape(0, shape(m)); hostDirty = false; deviceDirty = false; } void VkComBackendWrapper::copyToHost() { if (deviceDirty) copyToMat(*host, tensor); } void VkComBackendWrapper::setHostDirty() { hostDirty = true; }; void VkComBackendWrapper::setDeviceDirty() { deviceDirty = true; }; void VkComBackendWrapper::copyToDevice() { if (hostDirty) { copyToTensor(tensor, *host); hostDirty = false; } } vkcom::Tensor VkComBackendWrapper::getTensor() { return tensor; } Mat* VkComBackendWrapper::getMat() { return host; } #endif void forwardVkCom(std::vector > &outputs, const Ptr& node) { #ifdef HAVE_VULKAN CV_Assert(!node.empty()); Ptr node_ = node.dynamicCast(); CV_Assert(node_->forward()); setDirty(outputs); #endif } bool haveVulkan() { #ifdef HAVE_VULKAN return vkcom::isAvailable(); #else return false; #endif // HAVE_VULKAN } } // namespace dnn } // namespace cv