diff options
Diffstat (limited to 'Graphics/GraphicsEngineVulkan')
8 files changed, 176 insertions, 35 deletions
diff --git a/Graphics/GraphicsEngineVulkan/CMakeLists.txt b/Graphics/GraphicsEngineVulkan/CMakeLists.txt index 2ae05941..88dd3a11 100644 --- a/Graphics/GraphicsEngineVulkan/CMakeLists.txt +++ b/Graphics/GraphicsEngineVulkan/CMakeLists.txt @@ -30,6 +30,7 @@ set(INCLUDE include/SwapChainVkImpl.h include/TextureVkImpl.h include/TextureViewVkImpl.h + include/VulkanErrors.h ) set(VULKAN_UTILS_INCLUDE @@ -183,7 +184,7 @@ set_common_target_properties(GraphicsEngineVk-shared) set_common_target_properties(GraphicsEngineVk-static) source_group("src" FILES ${SRC}) -source_group("src\\vulkan utils" FILES ${VULKAN_UTILS_SRC}) +source_group("src\\Vulkan Utilities" FILES ${VULKAN_UTILS_SRC}) source_group("dll" FILES src/DLLMain.cpp @@ -192,7 +193,7 @@ source_group("dll" FILES source_group("include" FILES ${INCLUDE}) source_group("interface" FILES ${INTERFACE}) -source_group("include\\vulkan utils" FILES ${VULKAN_UTILS_INCLUDE}) +source_group("include\\Vulkan Utilities" FILES ${VULKAN_UTILS_INCLUDE}) #source_group("shaders" FILES # ${SHADERS} # shaders/GenerateMips/GenerateMipsCS.hlsli diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanErrors.h b/Graphics/GraphicsEngineVulkan/include/VulkanErrors.h new file mode 100644 index 00000000..d93c930b --- /dev/null +++ b/Graphics/GraphicsEngineVulkan/include/VulkanErrors.h @@ -0,0 +1,43 @@ +/* Copyright 2015-2018 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +#include "Errors.h" +#include "DebugUtilities.h" +#include "VulkanUtilities/VulkanDebug.h" + +#define CHECK_VK_ERROR(err, ...)\ +{ \ + if( err < 0 ) \ + { \ + LogError<false>(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__, "\nVK Error: ", VulkanUtilities::VkResultToString(err)); \ + UNEXPECTED("Error"); \ + } \ +} + +#define CHECK_VK_ERROR_AND_THROW(err, ...)\ +{ \ + if( err < 0 ) \ + LogError<true>(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__, "\nVK Error Code: ", VulkanUtilities::VkResultToString(err)); \ +} diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanInstance.h b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanInstance.h index 9937d613..346afeee 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanInstance.h +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanInstance.h @@ -40,7 +40,8 @@ namespace VulkanUtilities bool IsLayerAvailable(const char *LayerName)const; bool IsExtensionAvailable(const char *ExtensionName)const; VkPhysicalDevice SelectPhysicalDevice(); - + VkAllocationCallbacks* GetVkAllocator()const{return m_pVkAllocator;} + private: bool m_ValidationEnabled = false; diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.h b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.h index 76cd8bc8..2fb4d63a 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.h +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.h @@ -32,6 +32,9 @@ namespace VulkanUtilities { public: VulkanPhysicalDevice(VkPhysicalDevice vkDevice); + uint32_t FindQueueFamily(VkQueueFlags QueueFlags); + VkPhysicalDevice GetVkDeviceHandle()const{return m_VkDevice;} + bool IsExtensionSupported(const char *ExtensionName); private: const VkPhysicalDevice m_VkDevice; diff --git a/Graphics/GraphicsEngineVulkan/include/pch.h b/Graphics/GraphicsEngineVulkan/include/pch.h index ec0f4b00..7c623f11 100644 --- a/Graphics/GraphicsEngineVulkan/include/pch.h +++ b/Graphics/GraphicsEngineVulkan/include/pch.h @@ -28,8 +28,15 @@ #pragma once -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define NOMINMAX +#ifdef PLATFORM_WIN32 +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +# endif + +# ifndef NOMINMAX +# define NOMINMAX +# endif +#endif #include <vector> #include <exception> @@ -40,23 +47,7 @@ #include "PlatformDefinitions.h" #include "Errors.h" #include "RefCntAutoPtr.h" -#include "DebugUtilities.h" -//#include "D3DErrors.h" +#include "VulkanErrors.h" #include "RenderDeviceBase.h" #include "ValidatedCast.h" -#include <atlcomcli.h> - -#define CHECK_VK_ERROR(err, ...)\ -{ \ - if( err < 0 ) \ - { \ - LogError<false>(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__, "\nVK Error: ", VulkanUtilities::VkResultToString(err)); \ - UNEXPECTED("Error"); \ - } \ -} - -#define CHECK_VK_ERROR_AND_THROW(err, ...)\ -{ \ - if( err < 0 ) \ - LogError<true>(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__, "\nVK Error Code: ", VulkanUtilities::VkResultToString(err)); \ -} + diff --git a/Graphics/GraphicsEngineVulkan/src/RenderDeviceFactoryVk.cpp b/Graphics/GraphicsEngineVulkan/src/RenderDeviceFactoryVk.cpp index c3b4c5ea..fcafced8 100644 --- a/Graphics/GraphicsEngineVulkan/src/RenderDeviceFactoryVk.cpp +++ b/Graphics/GraphicsEngineVulkan/src/RenderDeviceFactoryVk.cpp @@ -123,6 +123,11 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk( const EngineVkAttribs& Crea if( !ppDevice || !ppContexts ) return; + SetRawAllocator(CreationAttribs.pRawMemAllocator); + + *ppDevice = nullptr; + memset(ppContexts, 0, sizeof(*ppContexts) * (1 + NumDeferredContexts)); + std::shared_ptr<VulkanUtilities::VulkanInstance> Instance; try { @@ -131,14 +136,51 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk( const EngineVkAttribs& Crea CreationAttribs.GlobalExtensionCount, CreationAttribs.ppGlobalExtensionNames, reinterpret_cast<VkAllocationCallbacks*>(CreationAttribs.pVkAllocator)); + + auto vkDevice = Instance->SelectPhysicalDevice(); + std::unique_ptr<VulkanUtilities::VulkanPhysicalDevice> PhysicalDevice(new VulkanUtilities::VulkanPhysicalDevice(vkDevice)); + + // If an implementation exposes any queue family that supports graphics operations, + // at least one queue family of at least one physical device exposed by the implementation + // must support both graphics and compute operations. + + VkDeviceQueueCreateInfo QueueInfo{}; + QueueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + // All commands that are allowed on a queue that supports transfer operations are also allowed on a + // queue that supports either graphics or compute operations.Thus, if the capabilities of a queue family + // include VK_QUEUE_GRAPHICS_BIT or VK_QUEUE_COMPUTE_BIT, then reporting the VK_QUEUE_TRANSFER_BIT + // capability separately for that queue family is optional. + QueueInfo.queueFamilyIndex = PhysicalDevice->FindQueueFamily(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT); + QueueInfo.queueCount = 1; + const float defaultQueuePriority = 1.0f; // Ask for highest priority for our queue. (range [0,1]) + QueueInfo.pQueuePriorities = &defaultQueuePriority; + + VkDeviceCreateInfo DeviceCreateInfo = {}; + DeviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + DeviceCreateInfo.queueCreateInfoCount = 1; + DeviceCreateInfo.pQueueCreateInfos = &QueueInfo; + DeviceCreateInfo.pEnabledFeatures = nullptr; + + std::vector<const char*> DeviceExtensions = { VK_KHR_SWAPCHAIN_EXTENSION_NAME }; + if (PhysicalDevice->IsExtensionSupported(VK_EXT_DEBUG_MARKER_EXTENSION_NAME)) + { + DeviceExtensions.push_back(VK_EXT_DEBUG_MARKER_EXTENSION_NAME); + } + + DeviceCreateInfo.ppEnabledExtensionNames = DeviceExtensions.empty() ? nullptr : DeviceExtensions.data(); + DeviceCreateInfo.enabledExtensionCount = static_cast<uint32_t>(DeviceExtensions.size()); + + VkDevice VulkanDevice = VK_NULL_HANDLE; + auto res = vkCreateDevice(PhysicalDevice->GetVkDeviceHandle(), &DeviceCreateInfo, Instance->GetVkAllocator(), &VulkanDevice); + CHECK_VK_ERROR_AND_THROW(res, "Failed to create logical device"); + + } catch(std::runtime_error& ) { return; } - auto vkDevice = Instance->SelectPhysicalDevice(); - std::unique_ptr<VulkanUtilities::VulkanPhysicalDevice> PhysicalDevice(new VulkanUtilities::VulkanPhysicalDevice(vkDevice)); @@ -160,10 +202,6 @@ void EngineFactoryVkImpl::CreateDeviceAndContextsVk( const EngineVkAttribs& Crea } } - SetRawAllocator(CreationAttribs.pRawMemAllocator); - - *ppDevice = nullptr; - memset(ppContexts, 0, sizeof(*ppContexts) * (1+NumDeferredContexts)); RefCntAutoPtr<CommandQueueVkImpl> pCmdQueueVk; CComPtr<IVkDevice> VkDevice; diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanInstance.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanInstance.cpp index 561d990f..6ea5f13a 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanInstance.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanInstance.cpp @@ -22,7 +22,7 @@ */ #include <vector> -#include "pch.h" +#include "VulkanErrors.h" #include "VulkanUtilities/VulkanInstance.h" #include "VulkanUtilities/VulkanDebug.h" @@ -193,20 +193,51 @@ namespace VulkanUtilities VkPhysicalDevice VulkanInstance::SelectPhysicalDevice() { + // Select a device that exposes a queue family that suppors both compute and graphics operations + // Prefer discrete GPU for (auto Device : m_PhysicalDevices) { VkPhysicalDeviceProperties DeviceProps; vkGetPhysicalDeviceProperties(Device, &DeviceProps); - if (DeviceProps.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) + + uint32_t QueueFamilyCount = 0; + vkGetPhysicalDeviceQueueFamilyProperties(Device, &QueueFamilyCount, nullptr); + VERIFY_EXPR(QueueFamilyCount> 0); + std::vector<VkQueueFamilyProperties> QueueFamilyProperties(QueueFamilyCount); + vkGetPhysicalDeviceQueueFamilyProperties(Device, &QueueFamilyCount, QueueFamilyProperties.data()); + VERIFY_EXPR(QueueFamilyCount == QueueFamilyProperties.size()); + + // If an implementation exposes any queue family that supports graphics operations, + // at least one queue family of at least one physical device exposed by the implementation + // must support both graphics and compute operations. + bool GraphicsAndComputeQueueSupported = false; + for(const auto &QueueFamilyProps : QueueFamilyProperties) + { + if( (QueueFamilyProps.queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0 && + (QueueFamilyProps.queueFlags & VK_QUEUE_COMPUTE_BIT) != 0) + { + GraphicsAndComputeQueueSupported = true; + break; + } + } + if(GraphicsAndComputeQueueSupported) { m_SelectedPhysicalDevice = Device; - LOG_INFO_MESSAGE("Selected discrete GPU ", DeviceProps.deviceName); - break; + if (DeviceProps.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) + break; } } - if(m_SelectedPhysicalDevice == VK_NULL_HANDLE) + if(m_SelectedPhysicalDevice != VK_NULL_HANDLE) + { + VkPhysicalDeviceProperties SelectedDeviceProps; + vkGetPhysicalDeviceProperties(m_SelectedPhysicalDevice, &SelectedDeviceProps); + LOG_INFO_MESSAGE("Using physical device ", SelectedDeviceProps.deviceName); + } + else + { LOG_ERROR_MESSAGE("Failed to find suitable physical device"); + } return m_SelectedPhysicalDevice; } diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp index f75e24b5..745923ee 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp @@ -21,7 +21,7 @@ * of the possibility of such damages. */ -#include "pch.h" +#include "VulkanErrors.h" #include "VulkanUtilities/VulkanPhysicalDevice.h" namespace VulkanUtilities @@ -52,4 +52,37 @@ namespace VulkanUtilities VERIFY_EXPR(ExtensionCount == m_SupportedExtensions.size()); } } + + uint32_t VulkanPhysicalDevice::FindQueueFamily(VkQueueFlags QueueFlags) + { + for(uint32_t i=0; i < m_QueueFamilyProperties.size(); ++i) + { + auto &Props = m_QueueFamilyProperties[i]; + if( (Props.queueFlags & QueueFlags) == QueueFlags) + { + if(QueueFlags & (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT)) + { + // Queues supporting graphics and/or compute operations must report (1,1,1) + // in minImageTransferGranularity, meaning that there are no additional restrictions + // on the granularity of image transfer operations for these queues. + VERIFY_EXPR(Props.minImageTransferGranularity.width == 1 && + Props.minImageTransferGranularity.height == 1 && + Props.minImageTransferGranularity.depth == 1); + return i; + } + } + } + + LOG_ERROR_AND_THROW("Failed to find suitable queue family"); + return 0; + } + + bool VulkanPhysicalDevice::IsExtensionSupported(const char *ExtensionName) + { + for(const auto& Extension : m_SupportedExtensions) + if(strcmp(Extension.extensionName, ExtensionName) == 0) + return true; + + return false; + } } |
