From 02cc1cd6e66cfe71e89324e03bfd2d12ae8911d7 Mon Sep 17 00:00:00 2001 From: WuZhiwen Date: Fri, 23 Nov 2018 00:46:30 +0800 Subject: [PATCH] Merge pull request #13244 from wzw-intel:init_vulkan * dnn/Vulkan: don't init Vulkan runtime if using other backend/target Don't need to explictly call a init API but will automatically init Vulkan environment the first time to use an VkCom object. Signed-off-by: Wu Zhiwen * dnn/Vulkan: depress compilier warning for "-Wsign-promo" Signed-off-by: Wu Zhiwen --- modules/dnn/src/dnn.cpp | 13 - modules/dnn/src/vkcom/include/op_base.hpp | 1 - modules/dnn/src/vkcom/include/vkcom.hpp | 3 - modules/dnn/src/vkcom/src/buffer.cpp | 2 +- modules/dnn/src/vkcom/src/common.hpp | 6 +- modules/dnn/src/vkcom/src/context.cpp | 296 +++++++++++++++ modules/dnn/src/vkcom/src/context.hpp | 10 +- modules/dnn/src/vkcom/src/op_base.cpp | 8 +- modules/dnn/src/vkcom/src/tensor.cpp | 8 +- modules/dnn/src/vkcom/src/vkcom.cpp | 403 --------------------- modules/dnn/src/vkcom/vulkan/vk_loader.hpp | 4 + 11 files changed, 318 insertions(+), 436 deletions(-) create mode 100644 modules/dnn/src/vkcom/src/context.cpp delete mode 100644 modules/dnn/src/vkcom/src/vkcom.cpp diff --git a/modules/dnn/src/dnn.cpp b/modules/dnn/src/dnn.cpp index cb38fafd77..58717c2a3a 100644 --- a/modules/dnn/src/dnn.cpp +++ b/modules/dnn/src/dnn.cpp @@ -911,21 +911,8 @@ struct Net::Impl typedef std::map LayersShapesMap; typedef std::map MapIdToLayerData; - ~Impl() - { -#ifdef HAVE_VULKAN - // Vulkan requires explicit releasing the child objects of - // VkDevice object prior to releasing VkDevice object itself. - layers.clear(); - backendWrappers.clear(); - vkcom::deinitPerThread(); -#endif - } Impl() { -#ifdef HAVE_VULKAN - vkcom::initPerThread(); -#endif //allocate fake net input layer netInputLayer = Ptr(new DataLayer()); LayerData &inpl = layers.insert( make_pair(0, LayerData()) ).first->second; diff --git a/modules/dnn/src/vkcom/include/op_base.hpp b/modules/dnn/src/vkcom/include/op_base.hpp index a44467062b..1ff2ee3bfa 100644 --- a/modules/dnn/src/vkcom/include/op_base.hpp +++ b/modules/dnn/src/vkcom/include/op_base.hpp @@ -36,7 +36,6 @@ protected: void recordCommandBuffer(void* push_constants = NULL, size_t push_constants_size = 0); void runCommandBuffer(); - const Context* ctx_; VkPipeline pipeline_; VkCommandBuffer cmd_buffer_; VkDescriptorPool descriptor_pool_; diff --git a/modules/dnn/src/vkcom/include/vkcom.hpp b/modules/dnn/src/vkcom/include/vkcom.hpp index 252b00b153..ee4f3be4a2 100644 --- a/modules/dnn/src/vkcom/include/vkcom.hpp +++ b/modules/dnn/src/vkcom/include/vkcom.hpp @@ -39,9 +39,6 @@ enum PaddingMode { kPaddingModeSame, kPaddingModeValid, kPaddingModeCaffe, kPadd enum FusedActivationType { kNone, kRelu, kRelu1, kRelu6, kActivationNum }; typedef std::vector Shape; -/* context APIs */ -bool initPerThread(); -void deinitPerThread(); bool isAvailable(); #endif // HAVE_VULKAN diff --git a/modules/dnn/src/vkcom/src/buffer.cpp b/modules/dnn/src/vkcom/src/buffer.cpp index 48083b55cc..401ac85b29 100644 --- a/modules/dnn/src/vkcom/src/buffer.cpp +++ b/modules/dnn/src/vkcom/src/buffer.cpp @@ -18,7 +18,7 @@ static uint32_t findMemoryType(uint32_t memoryTypeBits, VkMemoryPropertyFlags pr { VkPhysicalDeviceMemoryProperties memoryProperties; - vkGetPhysicalDeviceMemoryProperties(getPhysicalDevice(), &memoryProperties); + vkGetPhysicalDeviceMemoryProperties(kPhysicalDevice, &memoryProperties); for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; ++i) { if ((memoryTypeBits & (1 << i)) && diff --git a/modules/dnn/src/vkcom/src/common.hpp b/modules/dnn/src/vkcom/src/common.hpp index c976f87f7e..a7e3a27457 100644 --- a/modules/dnn/src/vkcom/src/common.hpp +++ b/modules/dnn/src/vkcom/src/common.hpp @@ -29,6 +29,10 @@ namespace cv { namespace dnn { namespace vkcom { #ifdef HAVE_VULKAN +extern VkPhysicalDevice kPhysicalDevice; +extern VkDevice kDevice; +extern VkQueue kQueue; +extern VkCommandPool kCmdPool; enum ShapeIdx { @@ -42,7 +46,7 @@ enum ShapeIdx { \ if (f != VK_SUCCESS) \ { \ - CV_LOG_ERROR(NULL, "Vulkan check failed, result = " << f); \ + CV_LOG_ERROR(NULL, "Vulkan check failed, result = " << (int)f); \ CV_Error(Error::StsError, "Vulkan check failed"); \ } \ } diff --git a/modules/dnn/src/vkcom/src/context.cpp b/modules/dnn/src/vkcom/src/context.cpp new file mode 100644 index 0000000000..2ec7cd2bc1 --- /dev/null +++ b/modules/dnn/src/vkcom/src/context.cpp @@ -0,0 +1,296 @@ +// 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 "../vulkan/vk_loader.hpp" +#include "common.hpp" +#include "context.hpp" + +namespace cv { namespace dnn { namespace vkcom { + +#ifdef HAVE_VULKAN + +std::shared_ptr kCtx; +bool enableValidationLayers = false; +VkInstance kInstance; +VkPhysicalDevice kPhysicalDevice; +VkDevice kDevice; +VkQueue kQueue; +VkCommandPool kCmdPool; +VkDebugReportCallbackEXT kDebugReportCallback; +uint32_t kQueueFamilyIndex; +std::vector kEnabledLayers; +std::map> kShaders; + +static uint32_t getComputeQueueFamilyIndex() +{ + uint32_t queueFamilyCount; + + vkGetPhysicalDeviceQueueFamilyProperties(kPhysicalDevice, &queueFamilyCount, NULL); + + std::vector queueFamilies(queueFamilyCount); + vkGetPhysicalDeviceQueueFamilyProperties(kPhysicalDevice, + &queueFamilyCount, + queueFamilies.data()); + + uint32_t i = 0; + for (; i < queueFamilies.size(); ++i) + { + VkQueueFamilyProperties props = queueFamilies[i]; + + if (props.queueCount > 0 && (props.queueFlags & VK_QUEUE_COMPUTE_BIT)) + { + break; + } + } + + if (i == queueFamilies.size()) + { + throw std::runtime_error("could not find a queue family that supports operations"); + } + + return i; +} + +bool checkExtensionAvailability(const char *extension_name, + const std::vector &available_extensions) +{ + for( size_t i = 0; i < available_extensions.size(); ++i ) + { + if( strcmp( available_extensions[i].extensionName, extension_name ) == 0 ) + { + return true; + } + } + return false; +} + +VKAPI_ATTR VkBool32 VKAPI_CALL debugReportCallbackFn( + VkDebugReportFlagsEXT flags, + VkDebugReportObjectTypeEXT objectType, + uint64_t object, + size_t location, + int32_t messageCode, + const char* pLayerPrefix, + const char* pMessage, + void* pUserData) +{ + std::cout << "Debug Report: " << pLayerPrefix << ":" << pMessage << std::endl; + return VK_FALSE; +} + +// internally used +void createContext() +{ + cv::AutoLock lock(getInitializationMutex()); + if (!kCtx) + { + kCtx.reset(new Context()); + } +} + +bool isAvailable() +{ + try + { + createContext(); + } + catch (const cv::Exception& e) + { + CV_LOG_ERROR(NULL, "Failed to init Vulkan environment. " << e.what()); + return false; + } + + return true; +} + +Context::Context() +{ + if(!loadVulkanLibrary()) + { + CV_Error(Error::StsError, "loadVulkanLibrary failed"); + return; + } + else if (!loadVulkanEntry()) + { + CV_Error(Error::StsError, "loadVulkanEntry failed"); + return; + } + else if (!loadVulkanGlobalFunctions()) + { + CV_Error(Error::StsError, "loadVulkanGlobalFunctions failed"); + return; + } + + // create VkInstance, VkPhysicalDevice + std::vector enabledExtensions; + if (enableValidationLayers) + { + uint32_t layerCount; + vkEnumerateInstanceLayerProperties(&layerCount, NULL); + + std::vector layerProperties(layerCount); + vkEnumerateInstanceLayerProperties(&layerCount, layerProperties.data()); + + bool foundLayer = false; + for (VkLayerProperties prop : layerProperties) + { + if (strcmp("VK_LAYER_LUNARG_standard_validation", prop.layerName) == 0) + { + foundLayer = true; + break; + } + } + + if (!foundLayer) + { + throw std::runtime_error("Layer VK_LAYER_LUNARG_standard_validation not supported\n"); + } + kEnabledLayers.push_back("VK_LAYER_LUNARG_standard_validation"); + + uint32_t extensionCount; + + vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, NULL); + std::vector extensionProperties(extensionCount); + vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensionProperties.data()); + + bool foundExtension = false; + for (VkExtensionProperties prop : extensionProperties) + { + if (strcmp(VK_EXT_DEBUG_REPORT_EXTENSION_NAME, prop.extensionName) == 0) + { + foundExtension = true; + break; + } + } + + if (!foundExtension) { + throw std::runtime_error("Extension VK_EXT_DEBUG_REPORT_EXTENSION_NAME not supported\n"); + } + enabledExtensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME); + } + + VkApplicationInfo applicationInfo = {}; + applicationInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + applicationInfo.pApplicationName = "VkCom Library"; + applicationInfo.applicationVersion = 0; + applicationInfo.pEngineName = "vkcom"; + applicationInfo.engineVersion = 0; + applicationInfo.apiVersion = VK_API_VERSION_1_0;; + + VkInstanceCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + createInfo.flags = 0; + createInfo.pApplicationInfo = &applicationInfo; + + // Give our desired layers and extensions to vulkan. + createInfo.enabledLayerCount = kEnabledLayers.size(); + createInfo.ppEnabledLayerNames = kEnabledLayers.data(); + createInfo.enabledExtensionCount = enabledExtensions.size(); + createInfo.ppEnabledExtensionNames = enabledExtensions.data(); + + VK_CHECK_RESULT(vkCreateInstance(&createInfo, NULL, &kInstance)); + + if (!loadVulkanFunctions(kInstance)) + { + CV_Error(Error::StsError, "loadVulkanFunctions failed"); + return; + } + + if (enableValidationLayers && vkCreateDebugReportCallbackEXT) + { + VkDebugReportCallbackCreateInfoEXT createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT; + createInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | + VK_DEBUG_REPORT_WARNING_BIT_EXT | + VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT; + createInfo.pfnCallback = &debugReportCallbackFn; + + // Create and register callback. + VK_CHECK_RESULT(vkCreateDebugReportCallbackEXT(kInstance, &createInfo, + NULL, &kDebugReportCallback)); + } + + // find physical device + uint32_t deviceCount; + vkEnumeratePhysicalDevices(kInstance, &deviceCount, NULL); + if (deviceCount == 0) + { + throw std::runtime_error("could not find a device with vulkan support"); + } + + std::vector devices(deviceCount); + vkEnumeratePhysicalDevices(kInstance, &deviceCount, devices.data()); + + for (VkPhysicalDevice device : devices) + { + if (true) + { + kPhysicalDevice = device; + break; + } + } + + kQueueFamilyIndex = getComputeQueueFamilyIndex(); + + // create device, queue, command pool + VkDeviceQueueCreateInfo queueCreateInfo = {}; + queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueCreateInfo.queueFamilyIndex = kQueueFamilyIndex; + queueCreateInfo.queueCount = 1; // create one queue in this family. We don't need more. + float queuePriorities = 1.0; // we only have one queue, so this is not that imporant. + queueCreateInfo.pQueuePriorities = &queuePriorities; + + VkDeviceCreateInfo deviceCreateInfo = {}; + + // Specify any desired device features here. We do not need any for this application, though. + VkPhysicalDeviceFeatures deviceFeatures = {}; + + deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + deviceCreateInfo.enabledLayerCount = kEnabledLayers.size(); + deviceCreateInfo.ppEnabledLayerNames = kEnabledLayers.data(); + deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo; + deviceCreateInfo.queueCreateInfoCount = 1; + deviceCreateInfo.pEnabledFeatures = &deviceFeatures; + + VK_CHECK_RESULT(vkCreateDevice(kPhysicalDevice, &deviceCreateInfo, NULL, &kDevice)); + + // Get a handle to the only member of the queue family. + vkGetDeviceQueue(kDevice, kQueueFamilyIndex, 0, &kQueue); + + // create command pool + VkCommandPoolCreateInfo commandPoolCreateInfo = {}; + commandPoolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + commandPoolCreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + // the queue family of this command pool. All command buffers allocated from this command pool, + // must be submitted to queues of this family ONLY. + commandPoolCreateInfo.queueFamilyIndex = kQueueFamilyIndex; + VK_CHECK_RESULT(vkCreateCommandPool(kDevice, &commandPoolCreateInfo, NULL, &kCmdPool)); +} + +Context::~Context() +{ + vkDestroyCommandPool(kDevice, kCmdPool, NULL); + vkDestroyDevice(kDevice, NULL); + + if (enableValidationLayers) { + auto func = (PFN_vkDestroyDebugReportCallbackEXT) + vkGetInstanceProcAddr(kInstance, "vkDestroyDebugReportCallbackEXT"); + if (func == nullptr) { + throw std::runtime_error("Could not load vkDestroyDebugReportCallbackEXT"); + } + func(kInstance, kDebugReportCallback, NULL); + } + kShaders.clear(); + vkDestroyInstance(kInstance, NULL); + + return; +} + +#endif // HAVE_VULKAN + +}}} // namespace cv::dnn::vkcom diff --git a/modules/dnn/src/vkcom/src/context.hpp b/modules/dnn/src/vkcom/src/context.hpp index f5505ce11e..a9d9d4de27 100644 --- a/modules/dnn/src/vkcom/src/context.hpp +++ b/modules/dnn/src/vkcom/src/context.hpp @@ -7,7 +7,6 @@ #ifndef OPENCV_DNN_VKCOM_CONTEXT_HPP #define OPENCV_DNN_VKCOM_CONTEXT_HPP -#include "common.hpp" namespace cv { namespace dnn { namespace vkcom { @@ -15,13 +14,12 @@ namespace cv { namespace dnn { namespace vkcom { struct Context { - VkDevice device; - VkQueue queue; - VkCommandPool cmd_pool; - std::map shader_modules; - int ref; + Context(); + ~Context(); }; +void createContext(); + #endif // HAVE_VULKAN }}} // namespace cv::dnn::vkcom diff --git a/modules/dnn/src/vkcom/src/op_base.cpp b/modules/dnn/src/vkcom/src/op_base.cpp index 6c7fa94d5e..95c0470b2e 100644 --- a/modules/dnn/src/vkcom/src/op_base.cpp +++ b/modules/dnn/src/vkcom/src/op_base.cpp @@ -16,8 +16,8 @@ namespace cv { namespace dnn { namespace vkcom { OpBase::OpBase() { - ctx_ = getContext(); - device_ = ctx_->device; + createContext(); + device_ = kDevice; pipeline_ = VK_NULL_HANDLE; cmd_buffer_ = VK_NULL_HANDLE; descriptor_pool_ = VK_NULL_HANDLE; @@ -139,7 +139,7 @@ void OpBase::createCommandBuffer() { VkCommandBufferAllocateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - info.commandPool = ctx_->cmd_pool; + info.commandPool = kCmdPool; info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; info.commandBufferCount = 1; VK_CHECK_RESULT(vkAllocateCommandBuffers(device_, &info, &cmd_buffer_)); @@ -176,7 +176,7 @@ void OpBase::runCommandBuffer() fence_create_info_.flags = 0; VK_CHECK_RESULT(vkCreateFence(device_, &fence_create_info_, NULL, &fence)); - VK_CHECK_RESULT(vkQueueSubmit(ctx_->queue, 1, &submit_info, fence)); + VK_CHECK_RESULT(vkQueueSubmit(kQueue, 1, &submit_info, fence)); VK_CHECK_RESULT(vkWaitForFences(device_, 1, &fence, VK_TRUE, 100000000000)); vkDestroyFence(device_, fence, NULL); } diff --git a/modules/dnn/src/vkcom/src/tensor.cpp b/modules/dnn/src/vkcom/src/tensor.cpp index eb5723e8ea..bbb50c857e 100644 --- a/modules/dnn/src/vkcom/src/tensor.cpp +++ b/modules/dnn/src/vkcom/src/tensor.cpp @@ -15,15 +15,15 @@ namespace cv { namespace dnn { namespace vkcom { Tensor::Tensor(Format fmt) : size_in_byte_(0), format_(fmt) { - Context *ctx = getContext(); - device_ = ctx->device; + createContext(); + device_ = kDevice; } Tensor::Tensor(const char* data, std::vector& shape, Format fmt) : size_in_byte_(0), format_(fmt) { - Context *ctx = getContext(); - device_ = ctx->device; + createContext(); + device_ = kDevice; reshape(data, shape); } diff --git a/modules/dnn/src/vkcom/src/vkcom.cpp b/modules/dnn/src/vkcom/src/vkcom.cpp deleted file mode 100644 index 16a4e3ab65..0000000000 --- a/modules/dnn/src/vkcom/src/vkcom.cpp +++ /dev/null @@ -1,403 +0,0 @@ -// 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 "common.hpp" -#include "internal.hpp" -#include "../include/op_conv.hpp" -#include "../include/op_pool.hpp" -#include "../include/op_lrn.hpp" -#include "../include/op_concat.hpp" -#include "../include/op_softmax.hpp" -#include "../vulkan/vk_loader.hpp" - -namespace cv { namespace dnn { namespace vkcom { - -#ifdef HAVE_VULKAN - -static bool enableValidationLayers = false; -static VkInstance kInstance; -static VkPhysicalDevice kPhysicalDevice; -static VkDebugReportCallbackEXT kDebugReportCallback; -static uint32_t kQueueFamilyIndex; -std::vector kEnabledLayers; -typedef std::map IdToContextMap; -IdToContextMap kThreadResources; -static std::map> kShaders; -static int init_count = 0; -static bool init(); -static void release(); -static uint32_t getComputeQueueFamilyIndex(); -static bool checkExtensionAvailability(const char *extension_name, - const std::vector - &available_extensions); -static VKAPI_ATTR VkBool32 VKAPI_CALL debugReportCallbackFn( - VkDebugReportFlagsEXT flags, - VkDebugReportObjectTypeEXT objectType, - uint64_t object, - size_t location, - int32_t messageCode, - const char* pLayerPrefix, - const char* pMessage, - void* pUserData); - -static void setContext(Context* ctx) -{ - cv::AutoLock lock(getInitializationMutex()); - std::thread::id tid = std::this_thread::get_id(); - if (kThreadResources.find(tid) != kThreadResources.end()) - { - return; - } - kThreadResources.insert(std::pair(tid, ctx)); -} - -Context* getContext() -{ - Context* ctx = NULL; - - cv::AutoLock lock(getInitializationMutex()); - std::thread::id tid = std::this_thread::get_id(); - IdToContextMap::iterator it = kThreadResources.find(tid); - if (it != kThreadResources.end()) - { - ctx = it->second; - } - return ctx; -} - -static void removeContext() -{ - cv::AutoLock lock(getInitializationMutex()); - std::thread::id tid = std::this_thread::get_id(); - IdToContextMap::iterator it = kThreadResources.find(tid); - if (it == kThreadResources.end()) - { - return; - } - kThreadResources.erase(it); -} - -bool initPerThread() -{ - VkDevice device; - VkQueue queue; - VkCommandPool cmd_pool; - - VKCOM_CHECK_BOOL_RET_VAL(init(), false); - Context* ctx = getContext(); - if (ctx) - { - ctx->ref++; - return true; - } - - // create device, queue, command pool - VkDeviceQueueCreateInfo queueCreateInfo = {}; - queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queueCreateInfo.queueFamilyIndex = kQueueFamilyIndex; - queueCreateInfo.queueCount = 1; // create one queue in this family. We don't need more. - float queuePriorities = 1.0; // we only have one queue, so this is not that imporant. - queueCreateInfo.pQueuePriorities = &queuePriorities; - - VkDeviceCreateInfo deviceCreateInfo = {}; - - // Specify any desired device features here. We do not need any for this application, though. - VkPhysicalDeviceFeatures deviceFeatures = {}; - - deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - deviceCreateInfo.enabledLayerCount = kEnabledLayers.size(); - deviceCreateInfo.ppEnabledLayerNames = kEnabledLayers.data(); - deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo; - deviceCreateInfo.queueCreateInfoCount = 1; - deviceCreateInfo.pEnabledFeatures = &deviceFeatures; - - VK_CHECK_RESULT(vkCreateDevice(kPhysicalDevice, &deviceCreateInfo, NULL, &device)); - - // Get a handle to the only member of the queue family. - vkGetDeviceQueue(device, kQueueFamilyIndex, 0, &queue); - - // create command pool - VkCommandPoolCreateInfo commandPoolCreateInfo = {}; - commandPoolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - commandPoolCreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - // the queue family of this command pool. All command buffers allocated from this command pool, - // must be submitted to queues of this family ONLY. - commandPoolCreateInfo.queueFamilyIndex = kQueueFamilyIndex; - VK_CHECK_RESULT(vkCreateCommandPool(device, &commandPoolCreateInfo, NULL, &cmd_pool)); - - ctx = new Context(); - ctx->device = device; - ctx->queue = queue; - ctx->cmd_pool = cmd_pool; - ctx->ref = 1; - setContext(ctx); - return true; -} - -void deinitPerThread() -{ - Context* ctx = getContext(); - if (ctx == NULL) - { - release(); - return; - } - - if (ctx->ref > 1) - { - ctx->ref--; - } - else if (ctx->ref == 1) - { - for(auto &kv: ctx->shader_modules) - { - vkDestroyShaderModule(ctx->device, kv.second, NULL); - } - ctx->shader_modules.clear(); - vkDestroyCommandPool(ctx->device, ctx->cmd_pool, NULL); - vkDestroyDevice(ctx->device, NULL); - removeContext(); - delete ctx; - } - else - CV_Assert(0); - release(); -} - -static bool init() -{ - cv::AutoLock lock(getInitializationMutex()); - - if (init_count == 0) - { - if(!loadVulkanLibrary()) - { - return false; - } - else if (!loadVulkanEntry()) - { - return false; - } - else if (!loadVulkanGlobalFunctions()) - { - return false; - } - - // create VkInstance, VkPhysicalDevice - std::vector enabledExtensions; - if (enableValidationLayers) - { - uint32_t layerCount; - vkEnumerateInstanceLayerProperties(&layerCount, NULL); - - std::vector layerProperties(layerCount); - vkEnumerateInstanceLayerProperties(&layerCount, layerProperties.data()); - - bool foundLayer = false; - for (VkLayerProperties prop : layerProperties) - { - if (strcmp("VK_LAYER_LUNARG_standard_validation", prop.layerName) == 0) - { - foundLayer = true; - break; - } - } - - if (!foundLayer) - { - throw std::runtime_error("Layer VK_LAYER_LUNARG_standard_validation not supported\n"); - } - kEnabledLayers.push_back("VK_LAYER_LUNARG_standard_validation"); - - uint32_t extensionCount; - - vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, NULL); - std::vector extensionProperties(extensionCount); - vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensionProperties.data()); - - bool foundExtension = false; - for (VkExtensionProperties prop : extensionProperties) - { - if (strcmp(VK_EXT_DEBUG_REPORT_EXTENSION_NAME, prop.extensionName) == 0) - { - foundExtension = true; - break; - } - } - - if (!foundExtension) { - throw std::runtime_error("Extension VK_EXT_DEBUG_REPORT_EXTENSION_NAME not supported\n"); - } - enabledExtensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME); - } - - VkApplicationInfo applicationInfo = {}; - applicationInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - applicationInfo.pApplicationName = "VkCom Library"; - applicationInfo.applicationVersion = 0; - applicationInfo.pEngineName = "vkcom"; - applicationInfo.engineVersion = 0; - applicationInfo.apiVersion = VK_API_VERSION_1_0;; - - VkInstanceCreateInfo createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; - createInfo.flags = 0; - createInfo.pApplicationInfo = &applicationInfo; - - // Give our desired layers and extensions to vulkan. - createInfo.enabledLayerCount = kEnabledLayers.size(); - createInfo.ppEnabledLayerNames = kEnabledLayers.data(); - createInfo.enabledExtensionCount = enabledExtensions.size(); - createInfo.ppEnabledExtensionNames = enabledExtensions.data(); - - VK_CHECK_RESULT(vkCreateInstance(&createInfo, NULL, &kInstance)); - - if (!loadVulkanFunctions(kInstance)) - { - return false; - } - - if (enableValidationLayers && vkCreateDebugReportCallbackEXT) - { - VkDebugReportCallbackCreateInfoEXT createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT; - createInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | - VK_DEBUG_REPORT_WARNING_BIT_EXT | - VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT; - createInfo.pfnCallback = &debugReportCallbackFn; - - // Create and register callback. - VK_CHECK_RESULT(vkCreateDebugReportCallbackEXT(kInstance, &createInfo, - NULL, &kDebugReportCallback)); - } - - // find physical device - uint32_t deviceCount; - vkEnumeratePhysicalDevices(kInstance, &deviceCount, NULL); - if (deviceCount == 0) - { - throw std::runtime_error("could not find a device with vulkan support"); - } - - std::vector devices(deviceCount); - vkEnumeratePhysicalDevices(kInstance, &deviceCount, devices.data()); - - for (VkPhysicalDevice device : devices) - { - if (true) - { - kPhysicalDevice = device; - break; - } - } - - kQueueFamilyIndex = getComputeQueueFamilyIndex(); - } - - init_count++; - return true; -} - -static void release() -{ - cv::AutoLock lock(getInitializationMutex()); - if (init_count == 0) - { - return; - } - - init_count--; - if (init_count == 0) - { - if (enableValidationLayers) { - auto func = (PFN_vkDestroyDebugReportCallbackEXT) - vkGetInstanceProcAddr(kInstance, "vkDestroyDebugReportCallbackEXT"); - if (func == nullptr) { - throw std::runtime_error("Could not load vkDestroyDebugReportCallbackEXT"); - } - func(kInstance, kDebugReportCallback, NULL); - } - kShaders.clear(); - vkDestroyInstance(kInstance, NULL); - } - - return; -} - -// Returns the index of a queue family that supports compute operations. -static uint32_t getComputeQueueFamilyIndex() -{ - uint32_t queueFamilyCount; - - vkGetPhysicalDeviceQueueFamilyProperties(kPhysicalDevice, &queueFamilyCount, NULL); - - std::vector queueFamilies(queueFamilyCount); - vkGetPhysicalDeviceQueueFamilyProperties(kPhysicalDevice, - &queueFamilyCount, - queueFamilies.data()); - - uint32_t i = 0; - for (; i < queueFamilies.size(); ++i) - { - VkQueueFamilyProperties props = queueFamilies[i]; - - if (props.queueCount > 0 && (props.queueFlags & VK_QUEUE_COMPUTE_BIT)) - { - break; - } - } - - if (i == queueFamilies.size()) - { - throw std::runtime_error("could not find a queue family that supports operations"); - } - - return i; -} - -bool checkExtensionAvailability(const char *extension_name, - const std::vector &available_extensions) -{ - for( size_t i = 0; i < available_extensions.size(); ++i ) - { - if( strcmp( available_extensions[i].extensionName, extension_name ) == 0 ) - { - return true; - } - } - return false; -} - -VKAPI_ATTR VkBool32 VKAPI_CALL debugReportCallbackFn( - VkDebugReportFlagsEXT flags, - VkDebugReportObjectTypeEXT objectType, - uint64_t object, - size_t location, - int32_t messageCode, - const char* pLayerPrefix, - const char* pMessage, - void* pUserData) -{ - std::cout << "Debug Report: " << pLayerPrefix << ":" << pMessage << std::endl; - return VK_FALSE; -} - -// internally used functions -VkPhysicalDevice getPhysicalDevice() -{ - return kPhysicalDevice; -} - -bool isAvailable() -{ - return getContext() != NULL; -} - -#endif // HAVE_VULKAN - -}}} // namespace cv::dnn::vkcom diff --git a/modules/dnn/src/vkcom/vulkan/vk_loader.hpp b/modules/dnn/src/vkcom/vulkan/vk_loader.hpp index aa8e98bcd9..df200226bb 100644 --- a/modules/dnn/src/vkcom/vulkan/vk_loader.hpp +++ b/modules/dnn/src/vkcom/vulkan/vk_loader.hpp @@ -8,6 +8,10 @@ #ifndef OPENCV_DNN_VKCOM_VULKAN_VK_LOADER_HPP #define OPENCV_DNN_VKCOM_VULKAN_VK_LOADER_HPP +#ifdef HAVE_VULKAN +#include +#endif // HAVE_VULKAN + namespace cv { namespace dnn { namespace vkcom { #ifdef HAVE_VULKAN