bool Tutorial01::CheckPhysicalDeviceProperties( VkPhysicalDevice physical_device, uint32_t &queue_family_index ) { VkPhysicalDeviceProperties device_properties; VkPhysicalDeviceFeatures device_features; vkGetPhysicalDeviceProperties( physical_device, &device_properties ); vkGetPhysicalDeviceFeatures( physical_device, &device_features ); uint32_t major_version = VK_VERSION_MAJOR( device_properties.apiVersion ); uint32_t minor_version = VK_VERSION_MINOR( device_properties.apiVersion ); uint32_t patch_version = VK_VERSION_PATCH( device_properties.apiVersion ); if( (major_version < 1) || (device_properties.limits.maxImageDimension2D < 4096) ) { std::cout << "Physical device " << physical_device << " doesn't support required parameters!" << std::endl; return false; } uint32_t queue_families_count = 0; vkGetPhysicalDeviceQueueFamilyProperties( physical_device, &queue_families_count, nullptr ); if( queue_families_count == 0 ) { std::cout << "Physical device " << physical_device << " doesn't have any queue families!" << std::endl; return false; } std::vector<VkQueueFamilyProperties> queue_family_properties( queue_families_count ); vkGetPhysicalDeviceQueueFamilyProperties( physical_device, &queue_families_count, queue_family_properties.data() ); for( uint32_t i = 0; i < queue_families_count; ++i ) { if( (queue_family_properties[i].queueCount > 0) && (queue_family_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) ) { queue_family_index = i; std::cout << "Selected device: " << device_properties.deviceName << std::endl; return true; } } std::cout << "Could not find queue family with required properties on physical device " << physical_device << "!" << std::endl; return false; }
bool vulkan_check_physical_device(IWindow* window, VkPhysicalDevice physical_device, VkSurfaceKHR presentationSurface, const std::vector<const char*>& extensions, uint32_t& queue_family_index, uint32_t& selected_present_queue_family_index) { Assert(window != nullptr); vulkan_device_check_extensions(extensions, physical_device); VkPhysicalDeviceProperties device_properties; VkPhysicalDeviceFeatures device_features; vkGetPhysicalDeviceProperties(physical_device, &device_properties); vkGetPhysicalDeviceFeatures(physical_device, &device_features); Assert(device_properties.apiVersion >= VK_MAKE_VERSION(1, 0, 0)); Assert(device_properties.limits.maxImageDimension2D >= 4096); Assert(device_features.shaderClipDistance == VK_TRUE); // This is just checked, not enabled uint32_t queue_families_count = 0; vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_families_count, nullptr); Assert(queue_families_count > 0, "device doesn't have any queue families"); if (queue_families_count == 0) return false; std::vector<VkQueueFamilyProperties> queue_family_properties(queue_families_count); std::vector<VkBool32> queue_present_support(queue_families_count); vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_families_count, &queue_family_properties[0]); uint32_t graphics_queue_family_index = UINT32_MAX; uint32_t present_queue_family_index = UINT32_MAX; for (uint32_t i = 0; i < queue_families_count; ++i) { Assert(vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, i, presentationSurface, &queue_present_support[i]) == VK_SUCCESS); if ((queue_family_properties[i].queueCount > 0) && (queue_family_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)) { // Select first queue that supports graphics if (graphics_queue_family_index == UINT32_MAX) graphics_queue_family_index = i; Assert(vulkan_queue_family_has_presentation_support(physical_device, i, window) == (queue_present_support[i] == VK_TRUE), "Queue family presentation support mismatch."); // If there is queue that supports both graphics and present - prefer it if (queue_present_support[i]) { queue_family_index = i; selected_present_queue_family_index = i; return true; } } } // We don't have queue that supports both graphics and present so we have to use separate queues for (uint32_t i = 0; i < queue_families_count; ++i) { if (queue_present_support[i] == VK_TRUE) { present_queue_family_index = i; break; } } Assert(graphics_queue_family_index != UINT32_MAX); Assert(present_queue_family_index != UINT32_MAX); queue_family_index = graphics_queue_family_index; selected_present_queue_family_index = present_queue_family_index; return true; }
bool VulkanContext::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer) { u32 queue_family_count; vkGetPhysicalDeviceQueueFamilyProperties(m_physical_device, &queue_family_count, nullptr); if (queue_family_count == 0) { ERROR_LOG(VIDEO, "No queue families found on specified vulkan physical device."); return false; } std::vector<VkQueueFamilyProperties> queue_family_properties(queue_family_count); vkGetPhysicalDeviceQueueFamilyProperties(m_physical_device, &queue_family_count, queue_family_properties.data()); INFO_LOG(VIDEO, "%u vulkan queue families", queue_family_count); // Find graphics and present queues. m_graphics_queue_family_index = queue_family_count; m_present_queue_family_index = queue_family_count; for (uint32_t i = 0; i < queue_family_count; i++) { VkBool32 graphics_supported = queue_family_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT; if (graphics_supported) { m_graphics_queue_family_index = i; // Quit now, no need for a present queue. if (!surface) { break; } } if (surface) { VkBool32 present_supported; VkResult res = vkGetPhysicalDeviceSurfaceSupportKHR(m_physical_device, i, surface, &present_supported); if (res != VK_SUCCESS) { LOG_VULKAN_ERROR(res, "vkGetPhysicalDeviceSurfaceSupportKHR failed: "); return false; } if (present_supported) { m_present_queue_family_index = i; } // Prefer one queue family index that does both graphics and present. if (graphics_supported && present_supported) { break; } } } if (m_graphics_queue_family_index == queue_family_count) { ERROR_LOG(VIDEO, "Vulkan: Failed to find an acceptable graphics queue."); return false; } if (surface && m_present_queue_family_index == queue_family_count) { ERROR_LOG(VIDEO, "Vulkan: Failed to find an acceptable present queue."); return false; } VkDeviceCreateInfo device_info = {}; device_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; device_info.pNext = nullptr; device_info.flags = 0; static constexpr float queue_priorities[] = {1.0f}; VkDeviceQueueCreateInfo graphics_queue_info = {}; graphics_queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; graphics_queue_info.pNext = nullptr; graphics_queue_info.flags = 0; graphics_queue_info.queueFamilyIndex = m_graphics_queue_family_index; graphics_queue_info.queueCount = 1; graphics_queue_info.pQueuePriorities = queue_priorities; VkDeviceQueueCreateInfo present_queue_info = {}; present_queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; present_queue_info.pNext = nullptr; present_queue_info.flags = 0; present_queue_info.queueFamilyIndex = m_present_queue_family_index; present_queue_info.queueCount = 1; present_queue_info.pQueuePriorities = queue_priorities; std::array<VkDeviceQueueCreateInfo, 2> queue_infos = {{ graphics_queue_info, present_queue_info, }}; device_info.queueCreateInfoCount = 1; if (m_graphics_queue_family_index != m_present_queue_family_index) { device_info.queueCreateInfoCount = 2; } device_info.pQueueCreateInfos = queue_infos.data(); ExtensionList enabled_extensions; if (!SelectDeviceExtensions(&enabled_extensions, surface != VK_NULL_HANDLE)) return false; device_info.enabledLayerCount = 0; device_info.ppEnabledLayerNames = nullptr; device_info.enabledExtensionCount = static_cast<uint32_t>(enabled_extensions.size()); device_info.ppEnabledExtensionNames = enabled_extensions.data(); // Check for required features before creating. if (!SelectDeviceFeatures()) return false; device_info.pEnabledFeatures = &m_device_features; // Enable debug layer on debug builds if (enable_validation_layer) { static const char* layer_names[] = {"VK_LAYER_LUNARG_standard_validation"}; device_info.enabledLayerCount = 1; device_info.ppEnabledLayerNames = layer_names; } VkResult res = vkCreateDevice(m_physical_device, &device_info, nullptr, &m_device); if (res != VK_SUCCESS) { LOG_VULKAN_ERROR(res, "vkCreateDevice failed: "); return false; } // With the device created, we can fill the remaining entry points. if (!LoadVulkanDeviceFunctions(m_device)) return false; // Grab the graphics and present queues. vkGetDeviceQueue(m_device, m_graphics_queue_family_index, 0, &m_graphics_queue); if (surface) { vkGetDeviceQueue(m_device, m_present_queue_family_index, 0, &m_present_queue); } return true; }
bool check_physical_device_properties(VkPhysicalDevice physical_device, uint32_t &selected_graphics_queue_family_index, uint32_t &selected_present_queue_family_index, const std::vector<const char *> &device_extensions) { uint32_t extensions_count = 0; if ((vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &extensions_count, nullptr) != VK_SUCCESS) || (extensions_count == 0)) { SET_ERROR (LOG_TYPE, "Error occurred during physical device %d extensions enumeration!", physical_device); return false; } std::vector<VkExtensionProperties> available_extensions(extensions_count); if (vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &extensions_count, &available_extensions[0]) != VK_SUCCESS) { SET_ERROR (LOG_TYPE, "Error occurred during physical device %d extensions enumeration!", physical_device); return false; } for (size_t i = 0; i < device_extensions.size(); ++i) { if (!utils::check_extension(device_extensions[i], available_extensions)) { SET_ERROR (LOG_TYPE, "Physical device %d doesn't support extension named \"%s\"!", physical_device, device_extensions[i]); return false; } } VkPhysicalDeviceProperties device_properties; VkPhysicalDeviceFeatures device_features; vkGetPhysicalDeviceProperties(physical_device, &device_properties); vkGetPhysicalDeviceFeatures(physical_device, &device_features); uint32_t major_version = VK_VERSION_MAJOR(device_properties.apiVersion); if ((major_version < 1) && (device_properties.limits.maxImageDimension2D < 4096)) { SET_ERROR (LOG_TYPE, "Physical device %d doesn't support required parameters!", physical_device); return false; } uint32_t queue_families_count = 0; vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_families_count, nullptr); if (queue_families_count == 0) { SET_ERROR (LOG_TYPE, "Physical device %d doesn't have any handle families!", physical_device); return false; } std::vector<VkQueueFamilyProperties> queue_family_properties(queue_families_count); std::vector<VkBool32> queue_present_support(queue_families_count); vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_families_count, &queue_family_properties[0]); uint32_t graphics_queue_family_index = UINT32_MAX; uint32_t present_queue_family_index = UINT32_MAX; for (uint32_t i = 0; i < queue_families_count; ++i) { vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, i, vk_globals::surface, &queue_present_support[i]); if ((queue_family_properties[i].queueCount > 0) && (queue_family_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)) { // Select first handle that supports graphics if (graphics_queue_family_index == UINT32_MAX) { graphics_queue_family_index = i; } // If there is handle that supports both graphics and present - prefer it if (queue_present_support[i]) { selected_graphics_queue_family_index = i; selected_present_queue_family_index = i; return true; } } } // We don't have handle that supports both graphics and present so we have to use separate queues for (uint32_t i = 0; i < queue_families_count; ++i) { if (queue_present_support[i]) { present_queue_family_index = i; break; } } // If this device doesn't support queues with graphics and present capabilities don't use it if ((graphics_queue_family_index == UINT32_MAX) || (present_queue_family_index == UINT32_MAX)) { SET_ERROR (LOG_TYPE, "Could not find handle families with required properties on physical device %d!", physical_device); return false; } selected_graphics_queue_family_index = graphics_queue_family_index; selected_present_queue_family_index = present_queue_family_index; return true; }
bool VulkanCommon::CheckPhysicalDeviceProperties( VkPhysicalDevice physical_device, uint32_t &selected_graphics_queue_family_index, uint32_t &selected_present_queue_family_index ) { uint32_t extensions_count = 0; if( (vkEnumerateDeviceExtensionProperties( physical_device, nullptr, &extensions_count, nullptr ) != VK_SUCCESS) || (extensions_count == 0) ) { std::cout << "Error occurred during physical device " << physical_device << " extensions enumeration!" << std::endl; return false; } std::vector<VkExtensionProperties> available_extensions( extensions_count ); if( vkEnumerateDeviceExtensionProperties( physical_device, nullptr, &extensions_count, &available_extensions[0] ) != VK_SUCCESS ) { std::cout << "Error occurred during physical device " << physical_device << " extensions enumeration!" << std::endl; return false; } std::vector<const char*> device_extensions = { VK_KHR_SWAPCHAIN_EXTENSION_NAME }; for( size_t i = 0; i < device_extensions.size(); ++i ) { if( !CheckExtensionAvailability( device_extensions[i], available_extensions ) ) { std::cout << "Physical device " << physical_device << " doesn't support extension named \"" << device_extensions[i] << "\"!" << std::endl; return false; } } VkPhysicalDeviceProperties device_properties; VkPhysicalDeviceFeatures device_features; vkGetPhysicalDeviceProperties( physical_device, &device_properties ); vkGetPhysicalDeviceFeatures( physical_device, &device_features ); uint32_t major_version = VK_VERSION_MAJOR( device_properties.apiVersion ); if( (major_version < 1) && (device_properties.limits.maxImageDimension2D < 4096) ) { std::cout << "Physical device " << physical_device << " doesn't support required parameters!" << std::endl; return false; } uint32_t queue_families_count = 0; vkGetPhysicalDeviceQueueFamilyProperties( physical_device, &queue_families_count, nullptr ); if( queue_families_count == 0 ) { std::cout << "Physical device " << physical_device << " doesn't have any queue families!" << std::endl; return false; } std::vector<VkQueueFamilyProperties> queue_family_properties( queue_families_count ); std::vector<VkBool32> queue_present_support( queue_families_count ); vkGetPhysicalDeviceQueueFamilyProperties( physical_device, &queue_families_count, &queue_family_properties[0] ); uint32_t graphics_queue_family_index = UINT32_MAX; uint32_t present_queue_family_index = UINT32_MAX; for( uint32_t i = 0; i < queue_families_count; ++i ) { vkGetPhysicalDeviceSurfaceSupportKHR( physical_device, i, Vulkan.PresentationSurface, &queue_present_support[i] ); if( (queue_family_properties[i].queueCount > 0) && (queue_family_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) ) { // Select first queue that supports graphics if( graphics_queue_family_index == UINT32_MAX ) { graphics_queue_family_index = i; } // If there is queue that supports both graphics and present - prefer it if( queue_present_support[i] ) { selected_graphics_queue_family_index = i; selected_present_queue_family_index = i; return true; } } } // We don't have queue that supports both graphics and present so we have to use separate queues for( uint32_t i = 0; i < queue_families_count; ++i ) { if( queue_present_support[i] ) { present_queue_family_index = i; break; } } // If this device doesn't support queues with graphics and present capabilities don't use it if( (graphics_queue_family_index == UINT32_MAX) || (present_queue_family_index == UINT32_MAX) ) { std::cout << "Could not find queue families with required properties on physical device " << physical_device << "!" << std::endl; return false; } selected_graphics_queue_family_index = graphics_queue_family_index; selected_present_queue_family_index = present_queue_family_index; return true; }
bool VulkanContext::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer) { u32 queue_family_count; vkGetPhysicalDeviceQueueFamilyProperties(m_physical_device, &queue_family_count, nullptr); if (queue_family_count == 0) { ERROR_LOG(VIDEO, "No queue families found on specified vulkan physical device."); return false; } std::vector<VkQueueFamilyProperties> queue_family_properties(queue_family_count); vkGetPhysicalDeviceQueueFamilyProperties(m_physical_device, &queue_family_count, queue_family_properties.data()); INFO_LOG(VIDEO, "%u vulkan queue families", queue_family_count); // Find a graphics queue // Currently we only use a single queue for both graphics and presenting. // TODO: In the future we could do post-processing and presenting on a different queue. m_graphics_queue_family_index = queue_family_count; for (uint32_t i = 0; i < queue_family_count; i++) { if (queue_family_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { // Check that it can present to our surface from this queue if (surface) { VkBool32 present_supported; VkResult res = vkGetPhysicalDeviceSurfaceSupportKHR(m_physical_device, i, surface, &present_supported); if (res != VK_SUCCESS) { LOG_VULKAN_ERROR(res, "vkGetPhysicalDeviceSurfaceSupportKHR failed: "); return false; } if (present_supported) { m_graphics_queue_family_index = i; break; } } else { // We don't need present, so any graphics queue will do. m_graphics_queue_family_index = i; break; } } } if (m_graphics_queue_family_index == queue_family_count) { ERROR_LOG(VIDEO, "Vulkan: Failed to find an acceptable graphics queue."); return false; } VkDeviceCreateInfo device_info = {}; device_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; device_info.pNext = nullptr; device_info.flags = 0; static constexpr float queue_priorities[] = {1.0f}; VkDeviceQueueCreateInfo queue_info = {}; queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queue_info.pNext = nullptr; queue_info.flags = 0; queue_info.queueFamilyIndex = m_graphics_queue_family_index; queue_info.queueCount = 1; queue_info.pQueuePriorities = queue_priorities; device_info.queueCreateInfoCount = 1; device_info.pQueueCreateInfos = &queue_info; ExtensionList enabled_extensions; if (!SelectDeviceExtensions(&enabled_extensions, (surface != VK_NULL_HANDLE), enable_validation_layer)) return false; device_info.enabledLayerCount = 0; device_info.ppEnabledLayerNames = nullptr; device_info.enabledExtensionCount = static_cast<uint32_t>(enabled_extensions.size()); device_info.ppEnabledExtensionNames = enabled_extensions.data(); // Check for required features before creating. if (!SelectDeviceFeatures()) return false; device_info.pEnabledFeatures = &m_device_features; // Enable debug layer on debug builds if (enable_validation_layer) { static const char* layer_names[] = {"VK_LAYER_LUNARG_standard_validation"}; device_info.enabledLayerCount = 1; device_info.ppEnabledLayerNames = layer_names; } VkResult res = vkCreateDevice(m_physical_device, &device_info, nullptr, &m_device); if (res != VK_SUCCESS) { LOG_VULKAN_ERROR(res, "vkCreateDevice failed: "); return false; } // With the device created, we can fill the remaining entry points. if (!LoadVulkanDeviceFunctions(m_device)) return false; // Grab the graphics queue (only one we're using at this point). vkGetDeviceQueue(m_device, m_graphics_queue_family_index, 0, &m_graphics_queue); return true; }