diff --git a/kraken/KRContext.cpp b/kraken/KRContext.cpp index 01a4556..58d7b75 100755 --- a/kraken/KRContext.cpp +++ b/kraken/KRContext.cpp @@ -809,11 +809,6 @@ void KRContext::destroyDeviceContexts() { const std::lock_guard lock(KRContext::g_DeviceInfoMutex); - for (auto itr = m_devices.begin(); itr != m_devices.end(); itr++) { - KRDevice* deviceInfo = &(*itr).second; - deviceInfo->destroy(); - } - m_devices.clear(); if (m_vulkanInstance != VK_NULL_HANDLE) { vkDestroyInstance(m_vulkanInstance, NULL); @@ -964,12 +959,12 @@ KrResult KRContext::createWindowSurface(const KrCreateWindowSurfaceInfo* createW } for (auto itr = m_devices.begin(); itr != m_devices.end(); itr++) { - KRDevice* device = &(*itr).second; + KRDevice& device = *(*itr).second; VkBool32 canPresent = false; - vkGetPhysicalDeviceSurfaceSupportKHR(device->m_device, device->m_graphicsFamilyQueueIndex, info.surface, &canPresent); + vkGetPhysicalDeviceSurfaceSupportKHR(device.m_device, device.m_graphicsFamilyQueueIndex, info.surface, &canPresent); if (canPresent) { info.deviceHandle = (*itr).first; - deviceInfo = device; + deviceInfo = &device; break; } } @@ -1301,7 +1296,7 @@ KRSurface& KRContext::GetSurfaceInfo(KrSurfaceHandle handle) KRDevice& KRContext::GetDeviceInfo(KrDeviceHandle handle) { - return m_devices[handle]; + return *m_devices[handle]; } void KRContext::createDevices() @@ -1316,175 +1311,49 @@ void KRContext::createDevices() return; } - std::vector devices(deviceCount); - vkEnumeratePhysicalDevices(m_vulkanInstance, &deviceCount, devices.data()); + std::vector physicalDevices(deviceCount); + vkEnumeratePhysicalDevices(m_vulkanInstance, &deviceCount, physicalDevices.data()); const std::vector deviceExtensions = { VK_KHR_SWAPCHAIN_EXTENSION_NAME }; - std::vector deviceInfos; + std::vector> candidateDevices; - for (const VkPhysicalDevice& device : devices) { - VkPhysicalDeviceProperties deviceProperties; - VkPhysicalDeviceFeatures deviceFeatures; - vkGetPhysicalDeviceProperties(device, &deviceProperties); - vkGetPhysicalDeviceFeatures(device, &deviceFeatures); - - uint32_t queueFamilyCount = 0; - vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr); - - std::vector queueFamilies(queueFamilyCount); - vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data()); - - uint32_t graphicsFamilyQueue = -1; - uint32_t computeFamilyQueue = -1; - uint32_t i = 0; - for (const auto& queueFamily : queueFamilies) { - if (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) { - graphicsFamilyQueue = i; - } - if (queueFamily.queueFlags & VK_QUEUE_COMPUTE_BIT) { - computeFamilyQueue = i; - } - i++; - } - if (graphicsFamilyQueue == -1) { - // No graphics queue family, not suitable - continue; - } - if (computeFamilyQueue == -1) { - // No compute queue family, not suitable - continue; - } - - uint32_t extensionCount; - vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr); - - std::vector availableExtensions(extensionCount); - vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data()); - - std::set requiredExtensions(deviceExtensions.begin(), deviceExtensions.end()); - - for (const auto& extension : availableExtensions) { - requiredExtensions.erase(extension.extensionName); - } - if (!requiredExtensions.empty()) { - // Missing a required extension + for (const VkPhysicalDevice& physicalDevice : physicalDevices) { + std::unique_ptr device = std::make_unique(physicalDevice); + if (!device->initialize(deviceExtensions)) { continue; } bool addDevice = false; - - - if (deviceInfos.empty()) { + if (candidateDevices.empty()) { addDevice = true; } else { - VkPhysicalDeviceType collectedType = deviceInfos[0].m_deviceProperties.deviceType; - if (collectedType == deviceProperties.deviceType) { + VkPhysicalDeviceType collectedType = candidateDevices[0]->m_deviceProperties.deviceType; + if (collectedType == device->m_deviceProperties.deviceType) { addDevice = true; - } else if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) { + } else if (device->m_deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) { // Discrete GPU's are always the best choice - deviceInfos.clear(); + candidateDevices.clear(); addDevice = true; - } else if (collectedType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU && deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) { + } else if (collectedType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU && device->m_deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) { // Integrated GPU's are the second best choice - deviceInfos.clear(); + candidateDevices.clear(); addDevice = true; - } else if (collectedType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU && collectedType != VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU && deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU) { + } else if (collectedType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU && collectedType != VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU && device->m_deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU) { // Virtual GPU's are the 3rd best choice - deviceInfos.clear(); + candidateDevices.clear(); addDevice = true; } } if (addDevice) { - KRDevice& info = deviceInfos.emplace_back(KRDevice{}); - info.m_device = device; - info.m_deviceProperties = deviceProperties; - info.m_deviceFeatures = deviceFeatures; - info.m_graphicsFamilyQueueIndex = graphicsFamilyQueue; - info.m_computeFamilyQueueIndex = computeFamilyQueue; + candidateDevices.push_back(std::move(device)); } } - for (KRDevice& info: deviceInfos) { - VkDeviceQueueCreateInfo queueCreateInfo[2]{}; - float queuePriority = 1.0f; - queueCreateInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queueCreateInfo[0].queueFamilyIndex = info.m_graphicsFamilyQueueIndex; - queueCreateInfo[0].queueCount = 1; - queueCreateInfo[0].pQueuePriorities = &queuePriority; - if (info.m_graphicsFamilyQueueIndex != info.m_computeFamilyQueueIndex) { - queueCreateInfo[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queueCreateInfo[1].queueFamilyIndex = info.m_computeFamilyQueueIndex; - queueCreateInfo[1].queueCount = 1; - queueCreateInfo[1].pQueuePriorities = &queuePriority; - } - - VkDeviceCreateInfo deviceCreateInfo{}; - deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - deviceCreateInfo.pQueueCreateInfos = queueCreateInfo; - deviceCreateInfo.queueCreateInfoCount = info.m_graphicsFamilyQueueIndex == info.m_computeFamilyQueueIndex ? 1 : 2; - VkPhysicalDeviceFeatures deviceFeatures{}; - deviceCreateInfo.pEnabledFeatures = &deviceFeatures; - deviceCreateInfo.enabledExtensionCount = static_cast(deviceExtensions.size()); - deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions.data(); - if (vkCreateDevice(info.m_device, &deviceCreateInfo, nullptr, &info.m_logicalDevice) != VK_SUCCESS) { - // TODO - Log a warning... - continue; - } - vkGetDeviceQueue(info.m_logicalDevice, info.m_graphicsFamilyQueueIndex, 0, &info.m_graphicsQueue); - vkGetDeviceQueue(info.m_logicalDevice, info.m_computeFamilyQueueIndex, 0, &info.m_computeQueue); - - VkCommandPoolCreateInfo poolInfo{}; - poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - poolInfo.queueFamilyIndex = info.m_graphicsFamilyQueueIndex; - poolInfo.flags = 0; - - if (vkCreateCommandPool(info.m_logicalDevice, &poolInfo, nullptr, &info.m_graphicsCommandPool) != VK_SUCCESS) { - vkDestroyDevice(info.m_logicalDevice, nullptr); - // TODO - Log a warning... - continue; - } - - poolInfo.queueFamilyIndex = info.m_computeFamilyQueueIndex; - if (vkCreateCommandPool(info.m_logicalDevice, &poolInfo, nullptr, &info.m_computeCommandPool) != VK_SUCCESS) { - vkDestroyCommandPool(info.m_logicalDevice, info.m_graphicsCommandPool, nullptr); - vkDestroyDevice(info.m_logicalDevice, nullptr); - // TODO - Log a warning... - continue; - } - - const int kMaxGraphicsCommandBuffers = 10; // TODO - This needs to be dynamic? - info.m_graphicsCommandBuffers.resize(kMaxGraphicsCommandBuffers); - - const int kMaxComputeCommandBuffers = 4; // TODO - This needs to be dynamic? - info.m_computeCommandBuffers.resize(kMaxComputeCommandBuffers); - - VkCommandBufferAllocateInfo allocInfo{}; - allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - allocInfo.commandPool = info.m_graphicsCommandPool; - allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - allocInfo.commandBufferCount = (uint32_t)info.m_graphicsCommandBuffers.size(); - - if (vkAllocateCommandBuffers(info.m_logicalDevice, &allocInfo, info.m_graphicsCommandBuffers.data()) != VK_SUCCESS) { - vkDestroyCommandPool(info.m_logicalDevice, info.m_computeCommandPool, nullptr); - vkDestroyCommandPool(info.m_logicalDevice, info.m_graphicsCommandPool, nullptr); - vkDestroyDevice(info.m_logicalDevice, nullptr); - // TODO - Log a warning - } - - allocInfo.commandPool = info.m_computeCommandPool; - allocInfo.commandBufferCount = (uint32_t)info.m_computeCommandBuffers.size(); - if (vkAllocateCommandBuffers(info.m_logicalDevice, &allocInfo, info.m_computeCommandBuffers.data()) != VK_SUCCESS) { - // Note - this repeated cleanup will likely be eliminated with later refactoring to split vulkan - // object generation out of KRContext - vkDestroyCommandPool(info.m_logicalDevice, info.m_computeCommandPool, nullptr); - vkDestroyCommandPool(info.m_logicalDevice, info.m_graphicsCommandPool, nullptr); - vkDestroyDevice(info.m_logicalDevice, nullptr); - // TODO - Log a warning - } - - m_devices[++m_topDeviceHandle] = info; + for (auto itr = candidateDevices.begin(); itr != candidateDevices.end(); itr++) { + std::unique_ptr device = std::move(*itr); + m_devices[++m_topDeviceHandle] = std::move(device); } } diff --git a/kraken/KRContext.h b/kraken/KRContext.h index 43ba736..7c90f45 100755 --- a/kraken/KRContext.h +++ b/kraken/KRContext.h @@ -215,7 +215,7 @@ private: std::atomic m_stop; void renderFrame(); - unordered_map m_devices; + unordered_map> m_devices; KrDeviceHandle m_topDeviceHandle; unordered_map m_surfaces; diff --git a/kraken/KRDevice.cpp b/kraken/KRDevice.cpp index 96f63eb..f1ba2f3 100644 --- a/kraken/KRDevice.cpp +++ b/kraken/KRDevice.cpp @@ -31,9 +31,175 @@ #include "KRDevice.h" +KRDevice::KRDevice(const VkPhysicalDevice& device) + : m_device(device) + , m_logicalDevice(VK_NULL_HANDLE) + , m_deviceProperties {} + , m_deviceFeatures{} + , m_graphicsFamilyQueueIndex(0) + , m_graphicsQueue(VK_NULL_HANDLE) + , m_computeFamilyQueueIndex(0) + , m_computeQueue(VK_NULL_HANDLE) + , m_graphicsCommandPool(VK_NULL_HANDLE) + , m_computeCommandPool(VK_NULL_HANDLE) +{ + +} + +KRDevice::~KRDevice() +{ + destroy(); +} + void KRDevice::destroy() { - vkDestroyCommandPool(m_logicalDevice, m_graphicsCommandPool, nullptr); - vkDestroyCommandPool(m_logicalDevice, m_computeCommandPool, nullptr); - vkDestroyDevice(m_logicalDevice, nullptr); + if (m_logicalDevice != VK_NULL_HANDLE) { + vkDestroyCommandPool(m_logicalDevice, m_graphicsCommandPool, nullptr); + m_graphicsCommandPool = VK_NULL_HANDLE; + } + + if (m_computeCommandPool != VK_NULL_HANDLE) { + vkDestroyCommandPool(m_logicalDevice, m_computeCommandPool, nullptr); + m_computeCommandPool = VK_NULL_HANDLE; + } + + if (m_logicalDevice != VK_NULL_HANDLE) { + vkDestroyDevice(m_logicalDevice, nullptr); + m_logicalDevice = VK_NULL_HANDLE; + } } + +bool KRDevice::initialize(const std::vector& deviceExtensions) +{ + vkGetPhysicalDeviceProperties(m_device, &m_deviceProperties); + vkGetPhysicalDeviceFeatures(m_device, &m_deviceFeatures); + + uint32_t queueFamilyCount = 0; + vkGetPhysicalDeviceQueueFamilyProperties(m_device, &queueFamilyCount, nullptr); + + std::vector queueFamilies(queueFamilyCount); + vkGetPhysicalDeviceQueueFamilyProperties(m_device, &queueFamilyCount, queueFamilies.data()); + + uint32_t graphicsFamilyQueue = -1; + uint32_t computeFamilyQueue = -1; + uint32_t i = 0; + for (const auto& queueFamily : queueFamilies) { + if (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) { + graphicsFamilyQueue = i; + } + if (queueFamily.queueFlags & VK_QUEUE_COMPUTE_BIT) { + computeFamilyQueue = i; + } + i++; + } + if (graphicsFamilyQueue == -1) { + // No graphics queue family, not suitable + return false; + } + + if (computeFamilyQueue == -1) { + // No compute queue family, not suitable + return false; + } + + m_graphicsFamilyQueueIndex = graphicsFamilyQueue; + m_computeFamilyQueueIndex = computeFamilyQueue; + + uint32_t extensionCount; + vkEnumerateDeviceExtensionProperties(m_device, nullptr, &extensionCount, nullptr); + + std::vector availableExtensions(extensionCount); + vkEnumerateDeviceExtensionProperties(m_device, nullptr, &extensionCount, availableExtensions.data()); + + std::set requiredExtensions(deviceExtensions.begin(), deviceExtensions.end()); + + for (const auto& extension : availableExtensions) { + requiredExtensions.erase(extension.extensionName); + } + if (!requiredExtensions.empty()) { + // Missing a required extension + return false; + } + + // ---- + + VkDeviceQueueCreateInfo queueCreateInfo[2]{}; + float queuePriority = 1.0f; + queueCreateInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueCreateInfo[0].queueFamilyIndex = m_graphicsFamilyQueueIndex; + queueCreateInfo[0].queueCount = 1; + queueCreateInfo[0].pQueuePriorities = &queuePriority; + if (m_graphicsFamilyQueueIndex != m_computeFamilyQueueIndex) { + queueCreateInfo[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueCreateInfo[1].queueFamilyIndex = m_computeFamilyQueueIndex; + queueCreateInfo[1].queueCount = 1; + queueCreateInfo[1].pQueuePriorities = &queuePriority; + } + + VkDeviceCreateInfo deviceCreateInfo{}; + deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + deviceCreateInfo.pQueueCreateInfos = queueCreateInfo; + deviceCreateInfo.queueCreateInfoCount = m_graphicsFamilyQueueIndex == m_computeFamilyQueueIndex ? 1 : 2; + VkPhysicalDeviceFeatures deviceFeatures{}; + deviceCreateInfo.pEnabledFeatures = &deviceFeatures; + deviceCreateInfo.enabledExtensionCount = static_cast(deviceExtensions.size()); + deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions.data(); + if (vkCreateDevice(m_device, &deviceCreateInfo, nullptr, &m_logicalDevice) != VK_SUCCESS) { + // TODO - Log a warning... + return false; + } + vkGetDeviceQueue(m_logicalDevice, m_graphicsFamilyQueueIndex, 0, &m_graphicsQueue); + vkGetDeviceQueue(m_logicalDevice, m_computeFamilyQueueIndex, 0, &m_computeQueue); + + VkCommandPoolCreateInfo poolInfo{}; + poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + poolInfo.queueFamilyIndex = m_graphicsFamilyQueueIndex; + poolInfo.flags = 0; + + if (vkCreateCommandPool(m_logicalDevice, &poolInfo, nullptr, &m_graphicsCommandPool) != VK_SUCCESS) { + vkDestroyDevice(m_logicalDevice, nullptr); + // TODO - Log a warning... + return false; + } + + poolInfo.queueFamilyIndex = m_computeFamilyQueueIndex; + if (vkCreateCommandPool(m_logicalDevice, &poolInfo, nullptr, &m_computeCommandPool) != VK_SUCCESS) { + vkDestroyCommandPool(m_logicalDevice, m_graphicsCommandPool, nullptr); + vkDestroyDevice(m_logicalDevice, nullptr); + // TODO - Log a warning... + return false; + } + + const int kMaxGraphicsCommandBuffers = 10; // TODO - This needs to be dynamic? + m_graphicsCommandBuffers.resize(kMaxGraphicsCommandBuffers); + + const int kMaxComputeCommandBuffers = 4; // TODO - This needs to be dynamic? + m_computeCommandBuffers.resize(kMaxComputeCommandBuffers); + + VkCommandBufferAllocateInfo allocInfo{}; + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.commandPool = m_graphicsCommandPool; + allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocInfo.commandBufferCount = (uint32_t)m_graphicsCommandBuffers.size(); + + if (vkAllocateCommandBuffers(m_logicalDevice, &allocInfo, m_graphicsCommandBuffers.data()) != VK_SUCCESS) { + vkDestroyCommandPool(m_logicalDevice, m_computeCommandPool, nullptr); + vkDestroyCommandPool(m_logicalDevice, m_graphicsCommandPool, nullptr); + vkDestroyDevice(m_logicalDevice, nullptr); + // TODO - Log a warning + return false; + } + + allocInfo.commandPool = m_computeCommandPool; + allocInfo.commandBufferCount = (uint32_t)m_computeCommandBuffers.size(); + if (vkAllocateCommandBuffers(m_logicalDevice, &allocInfo, m_computeCommandBuffers.data()) != VK_SUCCESS) { + // Note - this repeated cleanup will likely be eliminated with later refactoring to split vulkan + // object generation out of KRContext + vkDestroyCommandPool(m_logicalDevice, m_computeCommandPool, nullptr); + vkDestroyCommandPool(m_logicalDevice, m_graphicsCommandPool, nullptr); + vkDestroyDevice(m_logicalDevice, nullptr); + // TODO - Log a warning + return false; + } + return true; +} \ No newline at end of file diff --git a/kraken/KRDevice.h b/kraken/KRDevice.h index 77d01b8..a2c254e 100644 --- a/kraken/KRDevice.h +++ b/kraken/KRDevice.h @@ -37,8 +37,14 @@ class KRDevice { public: + KRDevice(const VkPhysicalDevice& device); + ~KRDevice(); + + KRDevice(const KRDevice&) = delete; + KRDevice& operator=(const KRDevice&) = delete; void destroy(); + bool initialize(const std::vector& deviceExtensions); VkPhysicalDevice m_device; VkDevice m_logicalDevice;