bool SwapChain::SelectPresentMode() { VkResult res; u32 mode_count; res = vkGetPhysicalDeviceSurfacePresentModesKHR(g_vulkan_context->GetPhysicalDevice(), m_surface, &mode_count, nullptr); if (res != VK_SUCCESS || mode_count == 0) { LOG_VULKAN_ERROR(res, "vkGetPhysicalDeviceSurfaceFormatsKHR failed: "); return false; } std::vector<VkPresentModeKHR> present_modes(mode_count); res = vkGetPhysicalDeviceSurfacePresentModesKHR(g_vulkan_context->GetPhysicalDevice(), m_surface, &mode_count, present_modes.data()); _assert_(res == VK_SUCCESS); // Checks if a particular mode is supported, if it is, returns that mode. auto CheckForMode = [&present_modes](VkPresentModeKHR check_mode) { auto it = std::find_if(present_modes.begin(), present_modes.end(), [check_mode](VkPresentModeKHR mode) { return check_mode == mode; }); return it != present_modes.end(); }; // If vsync is enabled, use VK_PRESENT_MODE_FIFO_KHR. // This check should not fail with conforming drivers, as the FIFO present mode is mandated by // the specification (VK_KHR_swapchain). In case it isn't though, fall through to any other mode. if (m_vsync_enabled && CheckForMode(VK_PRESENT_MODE_FIFO_KHR)) { m_present_mode = VK_PRESENT_MODE_FIFO_KHR; return true; } // Prefer screen-tearing, if possible, for lowest latency. if (CheckForMode(VK_PRESENT_MODE_IMMEDIATE_KHR)) { m_present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR; return true; } // Use optimized-vsync above vsync. if (CheckForMode(VK_PRESENT_MODE_MAILBOX_KHR)) { m_present_mode = VK_PRESENT_MODE_MAILBOX_KHR; return true; } // Fall back to whatever is available. m_present_mode = present_modes[0]; return true; }
VkResult setup(VkDevice device, VkCommandPool command_pool, SwapChain& swap_chain, uint32_t *width, uint32_t *height) { VkCommandBuffer setup_command_buffer = VK_NULL_HANDLE; // command buffer used for setup VkCommandBufferAllocateInfo command_buffer_allocate_info; command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; command_buffer_allocate_info.pNext = nullptr; command_buffer_allocate_info.commandPool = command_pool; command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; command_buffer_allocate_info.commandBufferCount = 1; vkAllocateCommandBuffers(device, &command_buffer_allocate_info, &setup_command_buffer); VkCommandBufferBeginInfo command_buffer_begin_info = {}; command_buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; command_buffer_begin_info.pNext = nullptr; command_buffer_begin_info.flags = 0; command_buffer_begin_info.pInheritanceInfo = nullptr; vkBeginCommandBuffer(setup_command_buffer, &command_buffer_begin_info); // SWAP CHAIN uint32_t present_mode_count = 0; vkGetPhysicalDeviceSurfacePresentModesKHR(swap_chain.gpu, swap_chain.surface, &present_mode_count, nullptr); std::vector<VkPresentModeKHR> present_modes(present_mode_count); vkGetPhysicalDeviceSurfacePresentModesKHR(swap_chain.gpu, swap_chain.surface, &present_mode_count, present_modes.data()); // Try to use mailbox mode // Low latency and non-tearing VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; for (uint32_t i = 0; i < present_mode_count; i++) { if (present_modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR; break; } if ((swapchainPresentMode != VK_PRESENT_MODE_MAILBOX_KHR) && (present_modes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR)) { swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; } } VkSurfaceCapabilitiesKHR surface_cap; vkGetPhysicalDeviceSurfaceCapabilitiesKHR(swap_chain.gpu, swap_chain.surface, &surface_cap); VkExtent2D swapchainExtent = {}; // width and height are either both -1, or both not -1. if (surface_cap.currentExtent.width == -1) { // If the surface size is undefined, the size is set to // the size of the images requested. swapchainExtent.width = *width; swapchainExtent.height = *height; } else { // If the surface size is defined, the swap chain size must match swapchainExtent = surface_cap.currentExtent; *width = surface_cap.currentExtent.width; *height = surface_cap.currentExtent.height; } // Determine the number of images uint32_t desired_number_of_swapchain_images = surface_cap.minImageCount + 1; if ((surface_cap.maxImageCount > 0) && (desired_number_of_swapchain_images > surface_cap.maxImageCount)) { desired_number_of_swapchain_images = surface_cap.maxImageCount; } VkSurfaceTransformFlagsKHR pre_transform; if (check_flag(surface_cap.supportedTransforms, VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)) { pre_transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; } else { pre_transform = surface_cap.currentTransform; } /* VkSwapchainCreateInfoKHR swapchain_creation_info = {}; swapchain_creation_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; swapchain_creation_info.pNext = NULL; swapchain_creation_info.surface = surface; swapchain_creation_info.minImageCount = desired_number_of_swapchain_images; swapchain_creation_info.imageFormat = colorFormat; swapchain_creation_info.imageColorSpace = colorSpace; swapchain_creation_info.imageExtent = { swapchainExtent.width, swapchainExtent.height }; swapchain_creation_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; swapchain_creation_info.preTransform = (VkSurfaceTransformFlagBitsKHR)preTransform; swapchain_creation_info.imageArrayLayers = 1; swapchain_creation_info.queueFamilyIndexCount = VK_SHARING_MODE_EXCLUSIVE; swapchain_creation_info.queueFamilyIndexCount = 0; swapchain_creation_info.pQueueFamilyIndices = NULL; swapchain_creation_info.presentMode = swapchainPresentMode; swapchain_creation_info.oldSwapchain = VK_NULL_HANDLE; swapchain_creation_info.clipped = true; swapchain_creation_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; vkCreateSwapchainKHR(device, &swapchain_creation_info, nullptr, &swap_chain.swap_chain); std::vector<VkImage> swap_chain_images(desired_number_of_swapchain_images); vkGetSwapchainImagesKHR(device, swapChain, &desired_number_of_swapchain_images, swap_chain_images.data()); */ /* assert(!err); buffers = (SwapChainBuffer*)malloc(sizeof(SwapChainBuffer)*imageCount); assert(buffers); //buffers.resize(imageCount); for (uint32_t i = 0; i < imageCount; i++) { VkImageViewCreateInfo colorAttachmentView = {}; colorAttachmentView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; colorAttachmentView.pNext = NULL; colorAttachmentView.format = colorFormat; colorAttachmentView.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }; colorAttachmentView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; colorAttachmentView.subresourceRange.baseMipLevel = 0; colorAttachmentView.subresourceRange.levelCount = 1; colorAttachmentView.subresourceRange.baseArrayLayer = 0; colorAttachmentView.subresourceRange.layerCount = 1; colorAttachmentView.viewType = VK_IMAGE_VIEW_TYPE_2D; colorAttachmentView.flags = 0; buffers[i].image = swapchainImages[i]; vkTools::setImageLayout( cmdBuffer, buffers[i].image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); colorAttachmentView.image = buffers[i].image; err = vkCreateImageView(device, &colorAttachmentView, nullptr, &buffers[i].view); assert(!err); } */ vkEndCommandBuffer(setup_command_buffer); VkSubmitInfo submit_info = {}; submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit_info.pNext = nullptr; submit_info.waitSemaphoreCount = 0; submit_info.pWaitSemaphores = nullptr; submit_info.pWaitDstStageMask = nullptr; submit_info.commandBufferCount = 1; submit_info.pCommandBuffers = &setup_command_buffer; submit_info.signalSemaphoreCount = 0; submit_info.pSignalSemaphores = nullptr; vkQueueSubmit(swap_chain.present_queue, 1, &submit_info, VK_NULL_HANDLE); vkQueueWaitIdle(swap_chain.present_queue); vkFreeCommandBuffers(device, command_pool, 1, &setup_command_buffer); 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(); }