bool SwapChain::SelectSurfaceFormat() { u32 format_count; VkResult res = vkGetPhysicalDeviceSurfaceFormatsKHR(g_vulkan_context->GetPhysicalDevice(), m_surface, &format_count, nullptr); if (res != VK_SUCCESS || format_count == 0) { LOG_VULKAN_ERROR(res, "vkGetPhysicalDeviceSurfaceFormatsKHR failed: "); return false; } std::vector<VkSurfaceFormatKHR> surface_formats(format_count); res = vkGetPhysicalDeviceSurfaceFormatsKHR(g_vulkan_context->GetPhysicalDevice(), m_surface, &format_count, surface_formats.data()); _assert_(res == VK_SUCCESS); // If there is a single undefined surface format, the device doesn't care, so we'll just use RGBA if (surface_formats[0].format == VK_FORMAT_UNDEFINED) { m_surface_format.format = VK_FORMAT_R8G8B8A8_UNORM; m_surface_format.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; return true; } // Use the first surface format, just use what it prefers. // Some drivers seem to return a SRGB format here (Intel Mesa). // This results in gamma correction when presenting to the screen, which we don't want. // Use a linear format instead, if this is the case. m_surface_format.format = Util::GetLinearFormat(surface_formats[0].format); m_surface_format.colorSpace = surface_formats[0].colorSpace; return true; }
VkResult create_surface(VkInstance vk_instance, VkPhysicalDevice gpu, VkDevice* out_device, DrawCommandBuffer* out_draw_command_buffer, SwapChain* out_swap_chain) { if ((out_swap_chain == nullptr) || (out_draw_command_buffer == nullptr)) { return VK_ERROR_INITIALIZATION_FAILED; } VkWin32SurfaceCreateInfoKHR surfaceCreateInfo; surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; surfaceCreateInfo.hinstance = out_swap_chain->instance; surfaceCreateInfo.hwnd = out_swap_chain->window; VK_THROW(vkCreateWin32SurfaceKHR(vk_instance, &surfaceCreateInfo, NULL, &(out_swap_chain->surface))); uint32_t queue_count; vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queue_count, nullptr); assert(queue_count > 0); std::vector<VkBool32> support_presentable_swap_chain(queue_count); std::vector<VkQueueFamilyProperties> properties(queue_count); vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queue_count, properties.data()); for (uint32_t qidx = 0; qidx < queue_count; ++qidx) { vkGetPhysicalDeviceSurfaceSupportKHR(gpu, qidx, out_swap_chain->surface, &(support_presentable_swap_chain[qidx])); } uint32_t graphics_queue = UINT32_MAX; uint32_t swap_chain_queue = UINT32_MAX; for (uint32_t qidx = 0; qidx < queue_count; ++qidx) { if (check_flag(properties[qidx].queueFlags, VK_QUEUE_GRAPHICS_BIT) && properties[qidx].queueCount > 0) { graphics_queue = qidx; if (support_presentable_swap_chain[qidx]) { swap_chain_queue = qidx; break; } } } if (swap_chain_queue == UINT32_MAX) // Can't find a graphic queue that also support swap chain. Select two different queue. { for (uint32_t qidx = 0; qidx < queue_count; ++qidx) { if (support_presentable_swap_chain[qidx] && (properties[qidx].queueCount > 0)) { swap_chain_queue = qidx; break; } } } // Generate error if could not find both a graphics and a present queue if ((graphics_queue == UINT32_MAX) || (swap_chain_queue == UINT32_MAX)) { vkDestroySurfaceKHR(vk_instance, out_swap_chain->surface, nullptr); out_swap_chain->surface = nullptr; return VK_ERROR_INITIALIZATION_FAILED; } uint32_t format_count; VK_THROW(vkGetPhysicalDeviceSurfaceFormatsKHR(gpu, out_swap_chain->surface, &format_count, NULL)); std::vector<VkSurfaceFormatKHR> surface_formats(format_count); VK_THROW(vkGetPhysicalDeviceSurfaceFormatsKHR(gpu, out_swap_chain->surface, &format_count, surface_formats.data())); // If the format list includes just one entry of VK_FORMAT_UNDEFINED, // the surface has no preferred format. Otherwise, at least one // supported format will be returned if (format_count == 1 && surface_formats[0].format == VK_FORMAT_UNDEFINED) { out_swap_chain->surface_format.format = VK_FORMAT_B8G8R8A8_UNORM; out_swap_chain->surface_format.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; } else { assert(format_count > 0); out_swap_chain->surface_format = surface_formats[0]; } VK_THROW(create_device(gpu, graphics_queue, swap_chain_queue, out_device)); vkGetDeviceQueue(*out_device, graphics_queue, 0, &out_draw_command_buffer->draw_queue); vkGetDeviceQueue(*out_device, swap_chain_queue, 0, &out_swap_chain->present_queue); out_draw_command_buffer->queue_family_idx = graphics_queue; out_swap_chain->queue_family_idx = swap_chain_queue; out_swap_chain->gpu = gpu; return VK_SUCCESS; }
bool VulkanCommon::CreateSwapChain() { if( Vulkan.Device != VK_NULL_HANDLE ) { vkDeviceWaitIdle( Vulkan.Device ); } for( size_t i = 0; i < Vulkan.SwapChain.Images.size(); ++i ) { if( Vulkan.SwapChain.Images[i].ImageView != VK_NULL_HANDLE ) { vkDestroyImageView( GetDevice(), Vulkan.SwapChain.Images[i].ImageView, nullptr ); Vulkan.SwapChain.Images[i].ImageView = VK_NULL_HANDLE; } } Vulkan.SwapChain.Images.clear(); VkSurfaceCapabilitiesKHR surface_capabilities; if( vkGetPhysicalDeviceSurfaceCapabilitiesKHR( Vulkan.PhysicalDevice, Vulkan.PresentationSurface, &surface_capabilities ) != VK_SUCCESS ) { std::cout << "Could not check presentation surface capabilities!" << std::endl; return false; } uint32_t formats_count; if( (vkGetPhysicalDeviceSurfaceFormatsKHR( Vulkan.PhysicalDevice, Vulkan.PresentationSurface, &formats_count, nullptr ) != VK_SUCCESS) || (formats_count == 0) ) { std::cout << "Error occurred during presentation surface formats enumeration!" << std::endl; return false; } std::vector<VkSurfaceFormatKHR> surface_formats( formats_count ); if( vkGetPhysicalDeviceSurfaceFormatsKHR( Vulkan.PhysicalDevice, Vulkan.PresentationSurface, &formats_count, &surface_formats[0] ) != VK_SUCCESS ) { std::cout << "Error occurred during presentation surface formats enumeration!" << std::endl; return false; } uint32_t present_modes_count; if( (vkGetPhysicalDeviceSurfacePresentModesKHR( Vulkan.PhysicalDevice, Vulkan.PresentationSurface, &present_modes_count, nullptr ) != VK_SUCCESS) || (present_modes_count == 0) ) { std::cout << "Error occurred during presentation surface present modes enumeration!" << std::endl; return false; } std::vector<VkPresentModeKHR> present_modes( present_modes_count ); if( vkGetPhysicalDeviceSurfacePresentModesKHR( Vulkan.PhysicalDevice, Vulkan.PresentationSurface, &present_modes_count, &present_modes[0] ) != VK_SUCCESS ) { std::cout << "Error occurred during presentation surface present modes enumeration!" << std::endl; return false; } uint32_t desired_number_of_images = GetSwapChainNumImages( surface_capabilities ); VkSurfaceFormatKHR desired_format = GetSwapChainFormat( surface_formats ); VkExtent2D desired_extent = GetSwapChainExtent( surface_capabilities ); VkImageUsageFlags desired_usage = GetSwapChainUsageFlags( surface_capabilities ); VkSurfaceTransformFlagBitsKHR desired_transform = GetSwapChainTransform( surface_capabilities ); VkPresentModeKHR desired_present_mode = GetSwapChainPresentMode( present_modes ); VkSwapchainKHR old_swap_chain = Vulkan.SwapChain.Handle; if( static_cast<int>(desired_usage) == -1 ) { return false; } if( static_cast<int>(desired_present_mode) == -1 ) { return false; } VkSwapchainCreateInfoKHR swap_chain_create_info = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, // VkStructureType sType nullptr, // const void *pNext 0, // VkSwapchainCreateFlagsKHR flags Vulkan.PresentationSurface, // VkSurfaceKHR surface desired_number_of_images, // uint32_t minImageCount desired_format.format, // VkFormat imageFormat desired_format.colorSpace, // VkColorSpaceKHR imageColorSpace desired_extent, // VkExtent2D imageExtent 1, // uint32_t imageArrayLayers desired_usage, // VkImageUsageFlags imageUsage VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode imageSharingMode 0, // uint32_t queueFamilyIndexCount nullptr, // const uint32_t *pQueueFamilyIndices desired_transform, // VkSurfaceTransformFlagBitsKHR preTransform VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, // VkCompositeAlphaFlagBitsKHR compositeAlpha desired_present_mode, // VkPresentModeKHR presentMode VK_TRUE, // VkBool32 clipped old_swap_chain // VkSwapchainKHR oldSwapchain }; if( vkCreateSwapchainKHR( Vulkan.Device, &swap_chain_create_info, nullptr, &Vulkan.SwapChain.Handle ) != VK_SUCCESS ) { std::cout << "Could not create swap chain!" << std::endl; return false; } if( old_swap_chain != VK_NULL_HANDLE ) { vkDestroySwapchainKHR( Vulkan.Device, old_swap_chain, nullptr ); } Vulkan.SwapChain.Format = desired_format.format; uint32_t image_count = 0; if( (vkGetSwapchainImagesKHR( Vulkan.Device, Vulkan.SwapChain.Handle, &image_count, nullptr ) != VK_SUCCESS) || (image_count == 0) ) { std::cout << "Could not get swap chain images!" << std::endl; return false; } Vulkan.SwapChain.Images.resize( image_count ); std::vector<VkImage> images( image_count ); if( vkGetSwapchainImagesKHR( Vulkan.Device, Vulkan.SwapChain.Handle, &image_count, &images[0] ) != VK_SUCCESS ) { std::cout << "Could not get swap chain images!" << std::endl; return false; } for( size_t i = 0; i < Vulkan.SwapChain.Images.size(); ++i ) { Vulkan.SwapChain.Images[i].Handle = images[i]; } Vulkan.SwapChain.Extent = desired_extent; return CreateSwapChainImageViews(); }
void configure_vulkan_wm_swapchain(ReaperRoot& root, const VulkanBackend& backend, const SwapchainDescriptor& swapchainDesc, PresentationInfo& presentInfo) { log_debug(root, "vulkan: configuring wm swapchain"); Assert( vkGetPhysicalDeviceSurfaceCapabilitiesKHR(backend.physicalDevice, presentInfo.surface, &presentInfo.surfaceCaps) == VK_SUCCESS); VkSurfaceCapabilitiesKHR& surfaceCaps = presentInfo.surfaceCaps; // Choose surface format VkSurfaceFormatKHR& surfaceFormat = presentInfo.surfaceFormat; { uint32_t formats_count; Assert( vkGetPhysicalDeviceSurfaceFormatsKHR(backend.physicalDevice, presentInfo.surface, &formats_count, nullptr) == VK_SUCCESS); Assert(formats_count > 0); std::vector<VkSurfaceFormatKHR> surface_formats(formats_count); Assert(vkGetPhysicalDeviceSurfaceFormatsKHR(backend.physicalDevice, presentInfo.surface, &formats_count, &surface_formats[0]) == VK_SUCCESS); log_debug(root, "vulkan: swapchain supports {} formats", formats_count); for (auto& format : surface_formats) log_debug(root, "- pixel format = {}, colorspace = {}", GetFormatToString(format.format), GetColorSpaceKHRToString(format.colorSpace)); surfaceFormat = vulkan_swapchain_choose_surface_format(surface_formats, swapchainDesc.preferredFormat); if (surfaceFormat.format != swapchainDesc.preferredFormat.format || surfaceFormat.colorSpace != swapchainDesc.preferredFormat.colorSpace) { // TODO format to_string() function log_warning(root, "vulkan: incompatible swapchain format: pixel format = {}, colorspace = {}", swapchainDesc.preferredFormat.format, swapchainDesc.preferredFormat.colorSpace); log_warning(root, "- falling back to: pixel format = {}, colorspace = {}", surfaceFormat.format, surfaceFormat.colorSpace); } } // Image count uint32_t imageCount = 0; { log_debug(root, "vulkan: swapchain image count support: min = {}, max = {}", surfaceCaps.minImageCount, surfaceCaps.maxImageCount); imageCount = swapchainDesc.preferredImageCount; if (imageCount < surfaceCaps.minImageCount) imageCount = surfaceCaps.minImageCount; else if (surfaceCaps.maxImageCount > 0 && imageCount > surfaceCaps.maxImageCount) imageCount = surfaceCaps.maxImageCount; if (imageCount != swapchainDesc.preferredImageCount) log_warning(root, "vulkan: swapchain image count {} is unsupported. falling back to {}", swapchainDesc.preferredImageCount, imageCount); Assert(imageCount > 0); Assert(imageCount < 4); // Seems like a reasonable limit presentInfo.imageCount = imageCount; } { uint32_t presentModeCount; Assert(vkGetPhysicalDeviceSurfacePresentModesKHR(backend.physicalDevice, presentInfo.surface, &presentModeCount, nullptr) == VK_SUCCESS); Assert(presentModeCount > 0); std::vector<VkPresentModeKHR> availablePresentModes(presentModeCount); Assert(vkGetPhysicalDeviceSurfacePresentModesKHR(backend.physicalDevice, presentInfo.surface, &presentModeCount, &availablePresentModes[0]) == VK_SUCCESS); log_debug(root, "vulkan: swapchain supports {} present modes", presentModeCount); for (auto& mode : availablePresentModes) log_debug(root, "- {}", GetPresentModeKHRToString(mode)); presentInfo.presentMode = vulkan_swapchain_choose_present_mode(availablePresentModes); } { VkExtent2D extent = vulkan_swapchain_choose_extent(surfaceCaps, swapchainDesc.preferredExtent); if (extent.width != swapchainDesc.preferredExtent.width || extent.height != swapchainDesc.preferredExtent.height) { log_warning(root, "vulkan: swapchain extent {}x{} is not supported", swapchainDesc.preferredExtent.width, swapchainDesc.preferredExtent.height); log_warning(root, "- falling back to {}x{}", extent.width, extent.height); } presentInfo.surfaceExtent = extent; } // Usage flags presentInfo.usageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; Assert((surfaceCaps.supportedUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) != 0, "Vulkan API error"); // Transform presentInfo.transform = vulkan_swapchain_choose_transform(surfaceCaps); }