Vulkan device initialization moved to KRDevice

This commit is contained in:
2021-08-16 18:25:03 -07:00
parent 748bd56b37
commit 61a83dd28d
4 changed files with 199 additions and 158 deletions

View File

@@ -809,11 +809,6 @@ void
KRContext::destroyDeviceContexts()
{
const std::lock_guard<std::mutex> 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<VkPhysicalDevice> devices(deviceCount);
vkEnumeratePhysicalDevices(m_vulkanInstance, &deviceCount, devices.data());
std::vector<VkPhysicalDevice> physicalDevices(deviceCount);
vkEnumeratePhysicalDevices(m_vulkanInstance, &deviceCount, physicalDevices.data());
const std::vector<const char*> deviceExtensions = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME
};
std::vector<KRDevice> deviceInfos;
std::vector<std::unique_ptr<KRDevice>> 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<VkQueueFamilyProperties> 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<VkExtensionProperties> availableExtensions(extensionCount);
vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data());
std::set<std::string> 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<KRDevice> device = std::make_unique<KRDevice>(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<uint32_t>(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<KRDevice> device = std::move(*itr);
m_devices[++m_topDeviceHandle] = std::move(device);
}
}

View File

@@ -215,7 +215,7 @@ private:
std::atomic<bool> m_stop;
void renderFrame();
unordered_map<KrDeviceHandle, KRDevice> m_devices;
unordered_map<KrDeviceHandle, std::unique_ptr<KRDevice>> m_devices;
KrDeviceHandle m_topDeviceHandle;
unordered_map<KrSurfaceHandle, KRSurface> m_surfaces;

View File

@@ -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<const char*>& deviceExtensions)
{
vkGetPhysicalDeviceProperties(m_device, &m_deviceProperties);
vkGetPhysicalDeviceFeatures(m_device, &m_deviceFeatures);
uint32_t queueFamilyCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties(m_device, &queueFamilyCount, nullptr);
std::vector<VkQueueFamilyProperties> 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<VkExtensionProperties> availableExtensions(extensionCount);
vkEnumerateDeviceExtensionProperties(m_device, nullptr, &extensionCount, availableExtensions.data());
std::set<std::string> 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<uint32_t>(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;
}

View File

@@ -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<const char*>& deviceExtensions);
VkPhysicalDevice m_device;
VkDevice m_logicalDevice;