SwapChainSupportDetails query_swap_chain_support(VkPhysicalDevice device) { SwapChainSupportDetails details; vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities); uint32_t formatCount; vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr); if (formatCount != 0) { details.formats.resize(formatCount); vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.formats.data()); } uint32_t presentModeCount; vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr); if (presentModeCount != 0) { details.presentModes.resize(presentModeCount); vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, details.presentModes.data()); } return details; }
bool getSurfacePresentModes() { u32 modesCount = 0; HR( vkGetPhysicalDeviceSurfacePresentModesKHR( gDevices[0], gSurface, &modesCount, nullptr ) ); gPresentModes.resize( modesCount ); HR( vkGetPhysicalDeviceSurfacePresentModesKHR( gDevices[0], gSurface, &modesCount, gPresentModes.data() ) ); return true; }
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; }
void Window::_InitSwapchain() { // This code is old and the fixed one is below // if( _swapchain_image_count > _surface_capabilities.maxImageCount ) _swapchain_image_count = _surface_capabilities.maxImageCount; // if( _swapchain_image_count < _surface_capabilities.minImageCount + 1 ) _swapchain_image_count = _surface_capabilities.minImageCount + 1; // The code above will work just fine in our tutorials and likely on every possible implementation of vulkan as well // so this change isn't that important. Just to be absolutely sure we don't go over or below the given limits we should check this a // little bit different though. maxImageCount can actually be zero in which case the amount of swapchain images do not have an // upper limit other than available memory. It's also possible that the swapchain image amount is locked to a certain // value on certain systems. The code below takes into consideration both of these possibilities. if( _swapchain_image_count < _surface_capabilities.minImageCount + 1 ) _swapchain_image_count = _surface_capabilities.minImageCount + 1; if( _surface_capabilities.maxImageCount > 0 ) { if( _swapchain_image_count > _surface_capabilities.maxImageCount ) _swapchain_image_count = _surface_capabilities.maxImageCount; } VkPresentModeKHR present_mode = VK_PRESENT_MODE_FIFO_KHR; { uint32_t present_mode_count = 0; ErrorCheck( vkGetPhysicalDeviceSurfacePresentModesKHR( _renderer->GetVulkanPhysicalDevice(), _surface, &present_mode_count, nullptr ) ); std::vector<VkPresentModeKHR> present_mode_list( present_mode_count ); ErrorCheck( vkGetPhysicalDeviceSurfacePresentModesKHR( _renderer->GetVulkanPhysicalDevice(), _surface, &present_mode_count, present_mode_list.data() ) ); for( auto m : present_mode_list ) { if( m == VK_PRESENT_MODE_MAILBOX_KHR ) present_mode = m; } } VkSwapchainCreateInfoKHR swapchain_create_info {}; swapchain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; swapchain_create_info.surface = _surface; swapchain_create_info.minImageCount = _swapchain_image_count; swapchain_create_info.imageFormat = _surface_format.format; swapchain_create_info.imageColorSpace = _surface_format.colorSpace; swapchain_create_info.imageExtent.width = _surface_size_x; swapchain_create_info.imageExtent.height = _surface_size_y; swapchain_create_info.imageArrayLayers = 1; swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; swapchain_create_info.queueFamilyIndexCount = 0; swapchain_create_info.pQueueFamilyIndices = nullptr; swapchain_create_info.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; swapchain_create_info.presentMode = present_mode; swapchain_create_info.clipped = VK_TRUE; swapchain_create_info.oldSwapchain = VK_NULL_HANDLE; ErrorCheck( vkCreateSwapchainKHR( _renderer->GetVulkanDevice(), &swapchain_create_info, nullptr, &_swapchain ) ); ErrorCheck( vkGetSwapchainImagesKHR( _renderer->GetVulkanDevice(), _swapchain, &_swapchain_image_count, nullptr ) ); }
void Window::_InitSwapchain() { if (_swapchain_image_count < _surface_capabilities.minImageCount) _swapchain_image_count = _surface_capabilities.minImageCount + 1; if (_swapchain_image_count > _surface_capabilities.maxImageCount) _swapchain_image_count = _surface_capabilities.maxImageCount; VkPresentModeKHR present_mode = VK_PRESENT_MODE_FIFO_KHR; { uint32_t present_mode_count = 0; ErrorCheck(vkGetPhysicalDeviceSurfacePresentModesKHR(_renderer->getPhysicalDevice(), _surface, &present_mode_count, nullptr)); std::vector<VkPresentModeKHR> present_mode_list(present_mode_count); ErrorCheck(vkGetPhysicalDeviceSurfacePresentModesKHR(_renderer->getPhysicalDevice(), _surface, &present_mode_count, present_mode_list.data())); for (auto m : present_mode_list) { if (m == VK_PRESENT_MODE_MAILBOX_KHR) present_mode = m; } } VkSwapchainCreateInfoKHR swapchain_create_info {}; swapchain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; swapchain_create_info.surface = _surface; swapchain_create_info.minImageCount = _swapchain_image_count; // Buffers swapchain_create_info.imageFormat = _surface_format.format; swapchain_create_info.imageColorSpace = _surface_format.colorSpace; swapchain_create_info.imageExtent.width = _surface_size_x; swapchain_create_info.imageExtent.height = _surface_size_y; swapchain_create_info.imageArrayLayers = 1; // Number of images (mono, stereo) swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; swapchain_create_info.queueFamilyIndexCount = 0; swapchain_create_info.pQueueFamilyIndices = nullptr; swapchain_create_info.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; swapchain_create_info.presentMode = present_mode; swapchain_create_info.clipped = VK_TRUE; swapchain_create_info.oldSwapchain = VK_NULL_HANDLE; ErrorCheck(vkCreateSwapchainKHR(_renderer->getDevice(), &swapchain_create_info, nullptr, &_swapchain)); ErrorCheck(vkGetSwapchainImagesKHR(_renderer->getDevice(), _swapchain, &_swapchain_image_count, nullptr)); }
void VulkanSwapChain::rebuild(const SPtr<VulkanDevice>& device, VkSurfaceKHR surface, UINT32 width, UINT32 height, bool vsync, VkFormat colorFormat, VkColorSpaceKHR colorSpace, bool createDepth, VkFormat depthFormat) { mDevice = device; VkResult result; VkPhysicalDevice physicalDevice = device->getPhysical(); // Determine swap chain dimensions VkSurfaceCapabilitiesKHR surfaceCaps; result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &surfaceCaps); assert(result == VK_SUCCESS); VkExtent2D swapchainExtent; // If width/height is 0xFFFFFFFF, we can manually specify width, height if (surfaceCaps.currentExtent.width == (uint32_t)-1 || surfaceCaps.currentExtent.height == (uint32_t)-1) { swapchainExtent.width = width; swapchainExtent.height = height; } else // Otherwise we must use the size we're given swapchainExtent = surfaceCaps.currentExtent; mWidth = swapchainExtent.width; mHeight = swapchainExtent.height; // Find present mode uint32_t numPresentModes; result = vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &numPresentModes, nullptr); assert(result == VK_SUCCESS); assert(numPresentModes > 0); VkPresentModeKHR* presentModes = bs_stack_alloc<VkPresentModeKHR>(numPresentModes); result = vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &numPresentModes, presentModes); assert(result == VK_SUCCESS); VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR; if(!vsync) { for (UINT32 i = 0; i < numPresentModes; i++) { if (presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) { presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; break; } if (presentModes[i] == VK_PRESENT_MODE_FIFO_RELAXED_KHR) presentMode = VK_PRESENT_MODE_FIFO_RELAXED_KHR; } } else { // Mailbox comes with lower input latency than FIFO, but can waste GPU power by rendering frames that are never // displayed, especially if the app runs much faster than the refresh rate. This is a concern for mobiles. #if BS_PLATFORM != BS_PLATFORM_ANDROID && BS_PLATFORM != BS_PLATFORM_IOS for (UINT32 i = 0; i < numPresentModes; i++) { if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { presentMode = VK_PRESENT_MODE_MAILBOX_KHR; break; } } #endif } bs_stack_free(presentModes); uint32_t numImages = surfaceCaps.minImageCount; VkSurfaceTransformFlagsKHR transform; if (surfaceCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; else transform = surfaceCaps.currentTransform; VkSwapchainCreateInfoKHR swapChainCI; swapChainCI.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; swapChainCI.pNext = nullptr; swapChainCI.flags = 0; swapChainCI.surface = surface; swapChainCI.minImageCount = numImages; swapChainCI.imageFormat = colorFormat; swapChainCI.imageColorSpace = colorSpace; swapChainCI.imageExtent = { swapchainExtent.width, swapchainExtent.height }; swapChainCI.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; swapChainCI.preTransform = (VkSurfaceTransformFlagBitsKHR)transform; swapChainCI.imageArrayLayers = 1; swapChainCI.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; swapChainCI.queueFamilyIndexCount = 0; swapChainCI.pQueueFamilyIndices = NULL; swapChainCI.presentMode = presentMode; swapChainCI.oldSwapchain = mSwapChain; swapChainCI.clipped = VK_TRUE; swapChainCI.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; VkSwapchainKHR oldSwapChain = mSwapChain; VkDevice logicalDevice = device->getLogical(); result = vkCreateSwapchainKHR(logicalDevice, &swapChainCI, gVulkanAllocator, &mSwapChain); assert(result == VK_SUCCESS); clear(oldSwapChain); result = vkGetSwapchainImagesKHR(logicalDevice, mSwapChain, &numImages, nullptr); assert(result == VK_SUCCESS); // Get the swap chain images VkImage* images = bs_stack_alloc<VkImage>(numImages); result = vkGetSwapchainImagesKHR(logicalDevice, mSwapChain, &numImages, images); assert(result == VK_SUCCESS); VulkanResourceManager& resManager = device->getResourceManager(); VULKAN_IMAGE_DESC imageDesc; imageDesc.format = colorFormat; imageDesc.type = TEX_TYPE_2D; imageDesc.usage = TU_RENDERTARGET; imageDesc.layout = VK_IMAGE_LAYOUT_UNDEFINED; imageDesc.numFaces = 1; imageDesc.numMipLevels = 1; imageDesc.memory = VK_NULL_HANDLE; mSurfaces.resize(numImages); for (UINT32 i = 0; i < numImages; i++) { imageDesc.image = images[i]; mSurfaces[i].acquired = false; mSurfaces[i].needsWait = false; mSurfaces[i].image = resManager.create<VulkanImage>(imageDesc, false); mSurfaces[i].sync = resManager.create<VulkanSemaphore>(); } bs_stack_free(images); // Create depth stencil image if (createDepth) { VkImageCreateInfo depthStencilImageCI; depthStencilImageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; depthStencilImageCI.pNext = nullptr; depthStencilImageCI.flags = 0; depthStencilImageCI.imageType = VK_IMAGE_TYPE_2D; depthStencilImageCI.format = depthFormat; depthStencilImageCI.extent = { width, height, 1 }; depthStencilImageCI.mipLevels = 1; depthStencilImageCI.arrayLayers = 1; depthStencilImageCI.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; depthStencilImageCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE; depthStencilImageCI.samples = VK_SAMPLE_COUNT_1_BIT; depthStencilImageCI.tiling = VK_IMAGE_TILING_OPTIMAL; depthStencilImageCI.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; depthStencilImageCI.pQueueFamilyIndices = nullptr; depthStencilImageCI.queueFamilyIndexCount = 0; VkImage depthStencilImage; result = vkCreateImage(logicalDevice, &depthStencilImageCI, gVulkanAllocator, &depthStencilImage); assert(result == VK_SUCCESS); imageDesc.image = depthStencilImage; imageDesc.usage = TU_DEPTHSTENCIL; imageDesc.format = depthFormat; imageDesc.memory = mDevice->allocateMemory(depthStencilImage, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); mDepthStencilImage = resManager.create<VulkanImage>(imageDesc, true); } else mDepthStencilImage = nullptr; // Create a framebuffer for each swap chain buffer UINT32 numFramebuffers = (UINT32)mSurfaces.size(); for (UINT32 i = 0; i < numFramebuffers; i++) { VULKAN_FRAMEBUFFER_DESC& desc = mSurfaces[i].framebufferDesc; desc.width = getWidth(); desc.height = getHeight(); desc.layers = 1; desc.numSamples = 1; desc.offscreen = false; desc.color[0].format = colorFormat; desc.color[0].image = mSurfaces[i].image; desc.color[0].surface = TextureSurface::COMPLETE; desc.color[0].baseLayer = 0; desc.depth.format = depthFormat; desc.depth.image = mDepthStencilImage; desc.depth.surface = TextureSurface::COMPLETE; desc.depth.baseLayer = 0; mSurfaces[i].framebuffer = resManager.create<VulkanFramebuffer>(desc); } }
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; }
static void setup_vulkan(GLFWwindow* window) { VkResult err; // Create Vulkan Instance { uint32_t extensions_count; const char** glfw_extensions = glfwGetRequiredInstanceExtensions(&extensions_count); VkInstanceCreateInfo create_info = {}; create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; create_info.enabledExtensionCount = extensions_count; create_info.ppEnabledExtensionNames = glfw_extensions; #ifdef IMGUI_VULKAN_DEBUG_REPORT // enabling multiple validation layers grouped as lunarg standard validation const char* layers[] = {"VK_LAYER_LUNARG_standard_validation"}; create_info.enabledLayerCount = 1; create_info.ppEnabledLayerNames = layers; // need additional storage for char pointer to debug report extension const char** extensions = (const char**)malloc(sizeof(const char*) * (extensions_count + 1)); for (size_t i = 0; i < extensions_count; i++) extensions[i] = glfw_extensions[i]; extensions[ extensions_count ] = "VK_EXT_debug_report"; create_info.enabledExtensionCount = extensions_count+1; create_info.ppEnabledExtensionNames = extensions; #endif // IMGUI_VULKAN_DEBUG_REPORT err = vkCreateInstance(&create_info, g_Allocator, &g_Instance); check_vk_result(err); #ifdef IMGUI_VULKAN_DEBUG_REPORT free(extensions); // create the debug report callback VkDebugReportCallbackCreateInfoEXT debug_report_ci ={}; debug_report_ci.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT; debug_report_ci.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT; debug_report_ci.pfnCallback = debug_report; debug_report_ci.pUserData = NULL; // get the proc address of the function pointer, required for used extensions PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(g_Instance, "vkCreateDebugReportCallbackEXT"); err = vkCreateDebugReportCallbackEXT( g_Instance, &debug_report_ci, g_Allocator, &g_Debug_Report ); check_vk_result(err); #endif // IMGUI_VULKAN_DEBUG_REPORT } // Create Window Surface { err = glfwCreateWindowSurface(g_Instance, window, g_Allocator, &g_Surface); check_vk_result(err); } // Get GPU { uint32_t gpu_count; err = vkEnumeratePhysicalDevices(g_Instance, &gpu_count, NULL); check_vk_result(err); VkPhysicalDevice* gpus = (VkPhysicalDevice*)malloc(sizeof(VkPhysicalDevice) * gpu_count); err = vkEnumeratePhysicalDevices(g_Instance, &gpu_count, gpus); check_vk_result(err); // If a number >1 of GPUs got reported, you should find the best fit GPU for your purpose // e.g. VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU if available, or with the greatest memory available, etc. // for sake of simplicity we'll just take the first one, assuming it has a graphics queue family. g_Gpu = gpus[0]; free(gpus); } // Get queue { uint32_t count; vkGetPhysicalDeviceQueueFamilyProperties(g_Gpu, &count, NULL); VkQueueFamilyProperties* queues = (VkQueueFamilyProperties*)malloc(sizeof(VkQueueFamilyProperties) * count); vkGetPhysicalDeviceQueueFamilyProperties(g_Gpu, &count, queues); for (uint32_t i = 0; i < count; i++) { if (queues[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { g_QueueFamily = i; break; } } free(queues); } // Check for WSI support { VkBool32 res; vkGetPhysicalDeviceSurfaceSupportKHR(g_Gpu, g_QueueFamily, g_Surface, &res); if (res != VK_TRUE) { fprintf(stderr, "Error no WSI support on physical device 0\n"); exit(-1); } } // Get Surface Format { // Per Spec Format and View Format are expected to be the same unless VK_IMAGE_CREATE_MUTABLE_BIT was set at image creation // Assuming that the default behavior is without setting this bit, there is no need for separate Spawchain image and image view format // additionally several new color spaces were introduced with Vulkan Spec v1.0.40 // hence we must make sure that a format with the mostly available color space, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, is found and used uint32_t count; vkGetPhysicalDeviceSurfaceFormatsKHR(g_Gpu, g_Surface, &count, NULL); VkSurfaceFormatKHR *formats = (VkSurfaceFormatKHR*)malloc(sizeof(VkSurfaceFormatKHR) * count); vkGetPhysicalDeviceSurfaceFormatsKHR(g_Gpu, g_Surface, &count, formats); // first check if only one format, VK_FORMAT_UNDEFINED, is available, which would imply that any format is available if (count == 1) { if( formats[0].format == VK_FORMAT_UNDEFINED ) { g_SurfaceFormat.format = VK_FORMAT_B8G8R8A8_UNORM; g_SurfaceFormat.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; } else { // no point in searching another format g_SurfaceFormat = formats[0]; } } else { // request several formats, the first found will be used VkFormat requestSurfaceImageFormat[] = {VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8_UNORM, VK_FORMAT_R8G8B8_UNORM}; VkColorSpaceKHR requestSurfaceColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; bool requestedFound = false; for (size_t i = 0; i < sizeof(requestSurfaceImageFormat) / sizeof(requestSurfaceImageFormat[0]); i++) { if( requestedFound ) { break; } for (uint32_t j = 0; j < count; j++) { if (formats[j].format == requestSurfaceImageFormat[i] && formats[j].colorSpace == requestSurfaceColorSpace) { g_SurfaceFormat = formats[j]; requestedFound = true; } } } // if none of the requested image formats could be found, use the first available if (!requestedFound) g_SurfaceFormat = formats[0]; } free(formats); } // Get Present Mode { // Requst a certain mode and confirm that it is available. If not use VK_PRESENT_MODE_FIFO_KHR which is mandatory #ifdef IMGUI_UNLIMITED_FRAME_RATE g_PresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; #else g_PresentMode = VK_PRESENT_MODE_FIFO_KHR; #endif uint32_t count = 0; vkGetPhysicalDeviceSurfacePresentModesKHR(g_Gpu, g_Surface, &count, nullptr); VkPresentModeKHR* presentModes = (VkPresentModeKHR*)malloc(sizeof(VkQueueFamilyProperties) * count); vkGetPhysicalDeviceSurfacePresentModesKHR(g_Gpu, g_Surface, &count, presentModes); bool presentModeAvailable = false; for (size_t i = 0; i < count; i++) { if (presentModes[i] == g_PresentMode) { presentModeAvailable = true; break; } } if( !presentModeAvailable ) g_PresentMode = VK_PRESENT_MODE_FIFO_KHR; // always available } // Create Logical Device { int device_extension_count = 1; const char* device_extensions[] = {"VK_KHR_swapchain"}; const uint32_t queue_index = 0; const uint32_t queue_count = 1; const float queue_priority[] = {1.0f}; VkDeviceQueueCreateInfo queue_info[1] = {}; queue_info[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queue_info[0].queueFamilyIndex = g_QueueFamily; queue_info[0].queueCount = queue_count; queue_info[0].pQueuePriorities = queue_priority; VkDeviceCreateInfo create_info = {}; create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; create_info.queueCreateInfoCount = sizeof(queue_info)/sizeof(queue_info[0]); create_info.pQueueCreateInfos = queue_info; create_info.enabledExtensionCount = device_extension_count; create_info.ppEnabledExtensionNames = device_extensions; err = vkCreateDevice(g_Gpu, &create_info, g_Allocator, &g_Device); check_vk_result(err); vkGetDeviceQueue(g_Device, g_QueueFamily, queue_index, &g_Queue); } // Create Framebuffers { int w, h; glfwGetFramebufferSize(window, &w, &h); resize_vulkan(window, w, h); glfwSetFramebufferSizeCallback(window, resize_vulkan); } // Create Command Buffers for (int i = 0; i < IMGUI_VK_QUEUED_FRAMES; i++) { { VkCommandPoolCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; info.queueFamilyIndex = g_QueueFamily; err = vkCreateCommandPool(g_Device, &info, g_Allocator, &g_CommandPool[i]); check_vk_result(err); } { VkCommandBufferAllocateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; info.commandPool = g_CommandPool[i]; info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; info.commandBufferCount = 1; err = vkAllocateCommandBuffers(g_Device, &info, &g_CommandBuffer[i]); check_vk_result(err); } { VkFenceCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; info.flags = VK_FENCE_CREATE_SIGNALED_BIT; err = vkCreateFence(g_Device, &info, g_Allocator, &g_Fence[i]); check_vk_result(err); } { VkSemaphoreCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; err = vkCreateSemaphore(g_Device, &info, g_Allocator, &g_PresentCompleteSemaphore[i]); check_vk_result(err); err = vkCreateSemaphore(g_Device, &info, g_Allocator, &g_RenderCompleteSemaphore[i]); check_vk_result(err); } } // Create Descriptor Pool { VkDescriptorPoolSize pool_size[11] = { { VK_DESCRIPTOR_TYPE_SAMPLER, 1000 }, { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1000 }, { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1000 }, { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1000 }, { VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1000 }, { VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1000 }, { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1000 }, { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1000 }, { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1000 }, { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1000 }, { VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1000 } }; VkDescriptorPoolCreateInfo pool_info = {}; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; pool_info.maxSets = 1000 * 11; pool_info.poolSizeCount = 11; pool_info.pPoolSizes = pool_size; err = vkCreateDescriptorPool(g_Device, &pool_info, g_Allocator, &g_DescriptorPool); check_vk_result(err); } }
/* Please see header for specification */ void Anvil::RenderingSurface::cache_surface_properties() { const Anvil::DeviceType& device_type (m_device_ptr->get_type() ); bool is_offscreen_rendering_enabled(true); auto khr_surface_entrypoints (m_create_info_ptr->get_instance_ptr()->get_extension_khr_surface_entrypoints() ); const Anvil::MGPUDevice* mgpu_device_ptr (dynamic_cast<const Anvil::MGPUDevice*>(m_device_ptr)); uint32_t n_physical_devices (0); const Anvil::SGPUDevice* sgpu_device_ptr (dynamic_cast<const Anvil::SGPUDevice*>(m_device_ptr)); std::vector<Anvil::SurfaceFormatKHR> supported_formats; auto window_ptr (m_create_info_ptr->get_window_ptr() ); if (window_ptr != nullptr) { const WindowPlatform window_platform(window_ptr->get_platform() ); is_offscreen_rendering_enabled = (window_platform == WINDOW_PLATFORM_DUMMY || window_platform == WINDOW_PLATFORM_DUMMY_WITH_PNG_SNAPSHOTS); if (is_offscreen_rendering_enabled) { m_height = window_ptr->get_height_at_creation_time(); m_width = window_ptr->get_width_at_creation_time (); } else { /* In this case, width & height may change at run-time */ } } else { /* In this case, width & height may change at run-time */ } switch (device_type) { case Anvil::DeviceType::MULTI_GPU: n_physical_devices = mgpu_device_ptr->get_n_physical_devices(); break; case Anvil::DeviceType::SINGLE_GPU: n_physical_devices = 1; break; default: { anvil_assert_fail(); } } /* Retrieve general properties */ uint32_t n_supported_formats (0); uint32_t n_supported_presentation_modes(0); VkResult result (VK_ERROR_INITIALIZATION_FAILED); ANVIL_REDUNDANT_VARIABLE(result); for (uint32_t n_physical_device = 0; n_physical_device < n_physical_devices; ++n_physical_device) { const Anvil::PhysicalDevice* physical_device_ptr = nullptr; switch (device_type) { case Anvil::DeviceType::MULTI_GPU: physical_device_ptr = mgpu_device_ptr->get_physical_device(n_physical_device); break; case Anvil::DeviceType::SINGLE_GPU: physical_device_ptr = sgpu_device_ptr->get_physical_device(); break; default: { anvil_assert_fail(); } } auto& result_caps = m_physical_device_capabilities[physical_device_ptr->get_device_group_device_index()]; if (m_surface == VK_NULL_HANDLE) { result_caps.supported_composite_alpha_flags = Anvil::CompositeAlphaFlagBits::INHERIT_BIT_KHR; result_caps.supported_transformations = Anvil::SurfaceTransformFlagBits::INHERIT_BIT_KHR; result_caps.supported_usages = static_cast<Anvil::ImageUsageFlags> (Anvil::ImageUsageFlagBits::COLOR_ATTACHMENT_BIT | Anvil::ImageUsageFlagBits::TRANSFER_SRC_BIT | Anvil::ImageUsageFlagBits::TRANSFER_DST_BIT | Anvil::ImageUsageFlagBits::STORAGE_BIT); result_caps.supported_presentation_modes.push_back(Anvil::PresentModeKHR::IMMEDIATE_KHR); continue; } const VkPhysicalDevice physical_device_vk = physical_device_ptr->get_physical_device(); result = khr_surface_entrypoints.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device_vk, m_surface, reinterpret_cast<VkSurfaceCapabilitiesKHR*>(&result_caps.capabilities) ); anvil_assert_vk_call_succeeded(result); if (n_physical_device == 0) { m_height = result_caps.capabilities.current_extent.height; m_width = result_caps.capabilities.current_extent.width; } else { anvil_assert(m_height == result_caps.capabilities.current_extent.height); anvil_assert(m_width == result_caps.capabilities.current_extent.width); } result_caps.supported_composite_alpha_flags = result_caps.capabilities.supported_composite_alpha; result_caps.supported_transformations = result_caps.capabilities.supported_transforms; result_caps.supported_usages = result_caps.capabilities.supported_usage_flags; /* Retrieve a list of formats supported by the surface */ result = khr_surface_entrypoints.vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device_vk, m_surface, &n_supported_formats, nullptr /* pSurfaceFormats */); anvil_assert (n_supported_formats > 0); anvil_assert_vk_call_succeeded(result); supported_formats.resize(n_supported_formats); result = khr_surface_entrypoints.vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device_vk, m_surface, &n_supported_formats, reinterpret_cast<VkSurfaceFormatKHR*>(&supported_formats.at(0) )); anvil_assert_vk_call_succeeded(result); for (unsigned int n_format = 0; n_format < n_supported_formats; ++n_format) { result_caps.supported_formats.push_back(RenderingSurfaceFormat(supported_formats[n_format]) ); } /* Retrieve a list of supported presentation modes * * NOTE: In case of mGPU devices, n_supported_presentation_modes may actually be 0 here for slave devices. */ result = khr_surface_entrypoints.vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device_vk, m_surface, &n_supported_presentation_modes, nullptr /* pPresentModes */); anvil_assert_vk_call_succeeded(result); if (n_supported_presentation_modes > 0) { std::vector<VkPresentModeKHR> temp_storage(n_supported_presentation_modes); result_caps.supported_presentation_modes.resize(n_supported_presentation_modes); result = khr_surface_entrypoints.vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device_vk, m_surface, &n_supported_presentation_modes, &temp_storage.at(0) ); anvil_assert_vk_call_succeeded(result); for (uint32_t n_presentation_mode = 0; n_presentation_mode < static_cast<uint32_t>(temp_storage.size() ); ++n_presentation_mode) { result_caps.supported_presentation_modes.at(n_presentation_mode) = static_cast<Anvil::PresentModeKHR>(temp_storage.at(n_presentation_mode) ); } } } }
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(); }
bool VkContext::CreateSwapchain(int width, int height) { // Get surface capabilities VkSurfaceCapabilitiesKHR surfaceCapabilities; CheckVkResult(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physDev, surf, &surfaceCapabilities)); // Get surface formats u32 formatCount = 0; CheckVkResult(vkGetPhysicalDeviceSurfaceFormatsKHR(physDev, surf, &formatCount, nullptr)); std::vector<VkSurfaceFormatKHR> formats(formatCount); CheckVkResult(vkGetPhysicalDeviceSurfaceFormatsKHR(physDev, surf, &formatCount, formats.data())); // Get present modes u32 presentModeCount; CheckVkResult(vkGetPhysicalDeviceSurfacePresentModesKHR(physDev, surf, &presentModeCount, nullptr)); std::vector<VkPresentModeKHR> presentModes(presentModeCount); CheckVkResult(vkGetPhysicalDeviceSurfacePresentModesKHR(physDev, surf, &presentModeCount, presentModes.data())); // Select number of swapchain images u32 imageCount = surfaceCapabilities.minImageCount + 1; if (surfaceCapabilities.maxImageCount != 0 && imageCount > surfaceCapabilities.maxImageCount) { imageCount = surfaceCapabilities.maxImageCount; } // Select format VkSurfaceFormatKHR format; if (formats.size() == 1 && formats[0].format == VK_FORMAT_UNDEFINED) { format.format = VK_FORMAT_R8G8B8A8_UNORM; format.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; } else { for (u32 i = 0; i < formats.size(); i++) { if (formats[i].format == VK_FORMAT_R8G8B8A8_UNORM) { format = formats[i]; } } format = formats[0]; } // Select extent VkExtent2D extent; if (surfaceCapabilities.currentExtent.width == -1) { extent.width = min(max((u32)width, surfaceCapabilities.minImageExtent.width), surfaceCapabilities.maxImageExtent.width); extent.height = min(max((u32)height, surfaceCapabilities.minImageExtent.height), surfaceCapabilities.maxImageExtent.height); } else { extent = surfaceCapabilities.currentExtent; } // Select present mode (FIFO by default) VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR; // Choose mailbox if possible for (u32 i = 0; i < presentModes.size(); i++) { if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { presentMode = presentModes[i]; } } // Select transformation VkSurfaceTransformFlagBitsKHR transform; if (surfaceCapabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) { transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; } else { transform = surfaceCapabilities.currentTransform; } // Check if image transfer destination is supported if (!(surfaceCapabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) { std::cout << "Image transfer destination not supported" << std::endl; return false; } // Create swapchian VkSwapchainCreateInfoKHR swapchainInfo = {}; swapchainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; swapchainInfo.surface = surf; swapchainInfo.minImageCount = imageCount; swapchainInfo.imageFormat = format.format; swapchainInfo.imageColorSpace = format.colorSpace; swapchainInfo.imageExtent = extent; swapchainInfo.imageArrayLayers = 1; swapchainInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; swapchainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; swapchainInfo.queueFamilyIndexCount = 0; swapchainInfo.pQueueFamilyIndices = nullptr; swapchainInfo.preTransform = transform; swapchainInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; swapchainInfo.presentMode = presentMode; swapchainInfo.clipped = VK_TRUE; swapchainInfo.oldSwapchain = VK_NULL_HANDLE; CheckVkResult(vkCreateSwapchainKHR(dev, &swapchainInfo, nullptr, &swapchain)); // Get swapchain images u32 swapchainImageCount = 0; CheckVkResult(vkGetSwapchainImagesKHR(dev, swapchain, &swapchainImageCount, nullptr)); swapchainImages.resize(swapchainImageCount); CheckVkResult(vkGetSwapchainImagesKHR(dev, swapchain, &swapchainImageCount, swapchainImages.data())); // Create swapchain image views swapchainImageViews.resize(imageCount); for (u32 i = 0; i < imageCount; i++) { VkImageViewCreateInfo imageViewCreateInfo = {}; imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; imageViewCreateInfo.image = swapchainImages[i]; imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; imageViewCreateInfo.format = format.format; imageViewCreateInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; imageViewCreateInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; imageViewCreateInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; imageViewCreateInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; imageViewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; imageViewCreateInfo.subresourceRange.baseMipLevel = 0; imageViewCreateInfo.subresourceRange.levelCount = 1; imageViewCreateInfo.subresourceRange.baseArrayLayer = 0; imageViewCreateInfo.subresourceRange.layerCount = 1; CheckVkResult(vkCreateImageView(dev, &imageViewCreateInfo, nullptr, &swapchainImageViews[i])); } return true; }
Error GrManagerImpl::initSwapchain(const GrManagerInitInfo& init) { VkSurfaceCapabilitiesKHR surfaceProperties; ANKI_VK_CHECK(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(m_physicalDevice, m_surface, &surfaceProperties)); if(surfaceProperties.currentExtent.width == MAX_U32 || surfaceProperties.currentExtent.height == MAX_U32) { ANKI_LOGE("Wrong surface size"); return ErrorCode::FUNCTION_FAILED; } m_surfaceWidth = surfaceProperties.currentExtent.width; m_surfaceHeight = surfaceProperties.currentExtent.height; uint32_t formatCount; ANKI_VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(m_physicalDevice, m_surface, &formatCount, nullptr)); DynamicArrayAuto<VkSurfaceFormatKHR> formats(getAllocator()); formats.create(formatCount); ANKI_VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(m_physicalDevice, m_surface, &formatCount, &formats[0])); VkColorSpaceKHR colorspace = VK_COLOR_SPACE_MAX_ENUM_KHR; while(formatCount--) { if(formats[formatCount].format == VK_FORMAT_B8G8R8A8_UNORM) { m_surfaceFormat = formats[formatCount].format; colorspace = formats[formatCount].colorSpace; break; } } if(m_surfaceFormat == VK_FORMAT_UNDEFINED) { ANKI_LOGE("Surface format not found"); return ErrorCode::FUNCTION_FAILED; } // Chose present mode uint32_t presentModeCount; vkGetPhysicalDeviceSurfacePresentModesKHR(m_physicalDevice, m_surface, &presentModeCount, nullptr); presentModeCount = min(presentModeCount, 4u); Array<VkPresentModeKHR, 4> presentModes; vkGetPhysicalDeviceSurfacePresentModesKHR(m_physicalDevice, m_surface, &presentModeCount, &presentModes[0]); VkPresentModeKHR presentMode = VK_PRESENT_MODE_MAX_ENUM_KHR; if(init.m_config->getNumber("vsync")) { presentMode = VK_PRESENT_MODE_FIFO_KHR; } else { for(U i = 0; i < presentModeCount; ++i) { if(presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { presentMode = VK_PRESENT_MODE_MAILBOX_KHR; break; } else if(presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) { presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; break; } } } if(presentMode == VK_PRESENT_MODE_MAX_ENUM_KHR) { ANKI_LOGE("VK: Couldn't find a present mode"); return ErrorCode::FUNCTION_FAILED; } // Create swapchain VkSwapchainCreateInfoKHR ci = {}; ci.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; ci.surface = m_surface; ci.minImageCount = MAX_FRAMES_IN_FLIGHT; ci.imageFormat = m_surfaceFormat; ci.imageColorSpace = colorspace; ci.imageExtent = surfaceProperties.currentExtent; ci.imageArrayLayers = 1; ci.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; ci.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; ci.queueFamilyIndexCount = 1; ci.pQueueFamilyIndices = &m_queueIdx; ci.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; ci.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; ci.presentMode = presentMode; ci.clipped = false; ci.oldSwapchain = VK_NULL_HANDLE; ANKI_VK_CHECK(vkCreateSwapchainKHR(m_device, &ci, nullptr, &m_swapchain)); // Get images uint32_t count = 0; ANKI_VK_CHECK(vkGetSwapchainImagesKHR(m_device, m_swapchain, &count, nullptr)); if(count != MAX_FRAMES_IN_FLIGHT) { ANKI_LOGE("Requested a swapchain with %u images but got one with %u", MAX_FRAMES_IN_FLIGHT, count); return ErrorCode::FUNCTION_FAILED; } ANKI_LOGI("VK: Created a swapchain. Image count: %u, present mode: %u", count, presentMode); Array<VkImage, MAX_FRAMES_IN_FLIGHT> images; ANKI_VK_CHECK(vkGetSwapchainImagesKHR(m_device, m_swapchain, &count, &images[0])); for(U i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) { m_backbuffers[i].m_image = images[i]; ANKI_ASSERT(images[i]); } // Create img views for(U i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) { VkImageViewCreateInfo ci = {}; ci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; ci.flags = 0; ci.image = m_backbuffers[i].m_image; ci.viewType = VK_IMAGE_VIEW_TYPE_2D; ci.format = m_surfaceFormat; ci.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A}; ci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; ci.subresourceRange.baseMipLevel = 0; ci.subresourceRange.levelCount = 1; ci.subresourceRange.baseArrayLayer = 0; ci.subresourceRange.layerCount = 1; ANKI_VK_CHECK(vkCreateImageView(m_device, &ci, nullptr, &m_backbuffers[i].m_imageView)); } return ErrorCode::NONE; }
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); }
Error MicroSwapchain::initInternal() { const VkDevice dev = m_factory->m_gr->getDevice(); // Get the surface size VkSurfaceCapabilitiesKHR surfaceProperties; U surfaceWidth = 0, surfaceHeight = 0; { ANKI_VK_CHECK(vkGetPhysicalDeviceSurfaceCapabilitiesKHR( m_factory->m_gr->getPhysicalDevice(), m_factory->m_gr->getSurface(), &surfaceProperties)); if(surfaceProperties.currentExtent.width == MAX_U32 || surfaceProperties.currentExtent.height == MAX_U32) { ANKI_VK_LOGE("Wrong surface size"); return Error::FUNCTION_FAILED; } surfaceWidth = surfaceProperties.currentExtent.width; surfaceHeight = surfaceProperties.currentExtent.height; } // Get the surface format VkFormat surfaceFormat = VK_FORMAT_END_RANGE; VkColorSpaceKHR colorspace = VK_COLOR_SPACE_MAX_ENUM_KHR; { uint32_t formatCount; ANKI_VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR( m_factory->m_gr->getPhysicalDevice(), m_factory->m_gr->getSurface(), &formatCount, nullptr)); DynamicArrayAuto<VkSurfaceFormatKHR> formats(getAllocator()); formats.create(formatCount); ANKI_VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR( m_factory->m_gr->getPhysicalDevice(), m_factory->m_gr->getSurface(), &formatCount, &formats[0])); while(formatCount--) { if(formats[formatCount].format == VK_FORMAT_B8G8R8A8_UNORM) { surfaceFormat = formats[formatCount].format; colorspace = formats[formatCount].colorSpace; break; } } if(surfaceFormat == VK_FORMAT_UNDEFINED) { ANKI_VK_LOGE("Surface format not found"); return Error::FUNCTION_FAILED; } } // Chose present mode VkPresentModeKHR presentMode = VK_PRESENT_MODE_MAX_ENUM_KHR; { uint32_t presentModeCount; vkGetPhysicalDeviceSurfacePresentModesKHR( m_factory->m_gr->getPhysicalDevice(), m_factory->m_gr->getSurface(), &presentModeCount, nullptr); presentModeCount = min(presentModeCount, 4u); Array<VkPresentModeKHR, 4> presentModes; vkGetPhysicalDeviceSurfacePresentModesKHR( m_factory->m_gr->getPhysicalDevice(), m_factory->m_gr->getSurface(), &presentModeCount, &presentModes[0]); if(m_factory->m_vsync) { presentMode = VK_PRESENT_MODE_FIFO_KHR; } else { for(U i = 0; i < presentModeCount; ++i) { if(presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { presentMode = VK_PRESENT_MODE_MAILBOX_KHR; break; } else if(presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) { presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; break; } } } if(presentMode == VK_PRESENT_MODE_MAX_ENUM_KHR) { ANKI_VK_LOGE("Couldn't find a present mode"); return Error::FUNCTION_FAILED; } } // Create swapchain { VkSwapchainCreateInfoKHR ci = {}; ci.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; ci.surface = m_factory->m_gr->getSurface(); ci.minImageCount = MAX_FRAMES_IN_FLIGHT; ci.imageFormat = surfaceFormat; ci.imageColorSpace = colorspace; ci.imageExtent = surfaceProperties.currentExtent; ci.imageArrayLayers = 1; ci.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; ci.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; ci.queueFamilyIndexCount = 1; U32 idx = m_factory->m_gr->getGraphicsQueueIndex(); ci.pQueueFamilyIndices = &idx; ci.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; ci.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; ci.presentMode = presentMode; ci.clipped = false; ci.oldSwapchain = VK_NULL_HANDLE; ANKI_VK_CHECK(vkCreateSwapchainKHR(dev, &ci, nullptr, &m_swapchain)); } // Get images { uint32_t count = 0; ANKI_VK_CHECK(vkGetSwapchainImagesKHR(dev, m_swapchain, &count, nullptr)); if(count != MAX_FRAMES_IN_FLIGHT) { ANKI_VK_LOGE("Requested a swapchain with %u images but got one with %u", MAX_FRAMES_IN_FLIGHT, count); return Error::FUNCTION_FAILED; } ANKI_VK_LOGI("Created a swapchain. Image count: %u, present mode: %u, size: %ux%u, vsync: %u", count, presentMode, surfaceWidth, surfaceHeight, U32(m_factory->m_vsync)); Array<VkImage, MAX_FRAMES_IN_FLIGHT> images; ANKI_VK_CHECK(vkGetSwapchainImagesKHR(dev, m_swapchain, &count, &images[0])); for(U i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) { TextureInitInfo init("SwapchainImg"); init.m_width = surfaceWidth; init.m_height = surfaceHeight; init.m_format = Format::B8G8R8A8_UNORM; ANKI_ASSERT(surfaceFormat == VK_FORMAT_B8G8R8A8_UNORM); init.m_usage = TextureUsageBit::IMAGE_COMPUTE_WRITE | TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ_WRITE | TextureUsageBit::PRESENT; init.m_type = TextureType::_2D; TextureImpl* tex = m_factory->m_gr->getAllocator().newInstance<TextureImpl>(m_factory->m_gr, init.getName()); m_textures[i].reset(tex); ANKI_CHECK(tex->initExternal(images[i], init)); } } return Error::NONE; }
//[-------------------------------------------------------] //[ Public methods ] //[-------------------------------------------------------] SwapChain::SwapChain(VulkanRenderer &vulkanRenderer, handle nativeWindowHandle) : ISwapChain(vulkanRenderer), mNativeWindowHandle(nativeWindowHandle), mVkSurfaceKHR(VK_NULL_HANDLE), mVkSwapchainKHR(VK_NULL_HANDLE), mSwapchainImageCount(0) { // Get the Vulkan instance and the Vulkan physical device const VkInstance vkInstance = vulkanRenderer.getVulkanRuntimeLinking().getVkInstance(); const IContext& context = vulkanRenderer.getContext(); const VkPhysicalDevice vkPhysicalDevice = context.getVkPhysicalDevice(); const VkDevice vkDevice = context.getVkDevice(); // Create Vulkan surface instance depending on OS #ifdef _WIN32 VkWin32SurfaceCreateInfoKHR vkWin32SurfaceCreateInfoKHR = {}; vkWin32SurfaceCreateInfoKHR.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; vkWin32SurfaceCreateInfoKHR.hinstance = reinterpret_cast<HINSTANCE>(::GetWindowLong(reinterpret_cast<HWND>(nativeWindowHandle), GWL_HINSTANCE)); vkWin32SurfaceCreateInfoKHR.hwnd = reinterpret_cast<HWND>(nativeWindowHandle); VkResult vkResult = vkCreateWin32SurfaceKHR(vkInstance, &vkWin32SurfaceCreateInfoKHR, nullptr, &mVkSurfaceKHR); #else #ifdef __ANDROID__ // TODO(co) Not tested - see https://github.com/SaschaWillems/Vulkan VkAndroidSurfaceCreateInfoKHR vkAndroidSurfaceCreateInfoKHR = {}; vkAndroidSurfaceCreateInfoKHR.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR; vkAndroidSurfaceCreateInfoKHR.window = window; VkResult vkResult = vkCreateAndroidSurfaceKHR(vkInstance, &vkAndroidSurfaceCreateInfoKHR, nullptr, &mVkSurfaceKHR); #else // TODO(co) Not tested - see https://github.com/SaschaWillems/Vulkan VkXcbSurfaceCreateInfoKHR vkXcbSurfaceCreateInfoKHR = {}; vkXcbSurfaceCreateInfoKHR.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; vkXcbSurfaceCreateInfoKHR.connection = connection; vkXcbSurfaceCreateInfoKHR.window = window; VkResult vkResult = vkCreateXcbSurfaceKHR(vkInstance, &vkXcbSurfaceCreateInfoKHR, nullptr, &mVkSurfaceKHR); #endif #endif // Get list of supported surface formats uint32_t surfaceFormatCount = 0; vkResult = vkGetPhysicalDeviceSurfaceFormatsKHR(vkPhysicalDevice, mVkSurfaceKHR, &surfaceFormatCount, nullptr); // assert(!vkResult); // assert(surfaceFormatCount > 0); std::vector<VkSurfaceFormatKHR> vkSurfaceFormatKHRs(surfaceFormatCount); vkResult = vkGetPhysicalDeviceSurfaceFormatsKHR(vkPhysicalDevice, mVkSurfaceKHR, &surfaceFormatCount, vkSurfaceFormatKHRs.data()); // assert(!vkResult); // If the surface format list only includes one entry with VK_FORMAT_UNDEFINED, // there is no preferred format, so we assume VK_FORMAT_B8G8R8A8_UNORM VkFormat colorVkFormat; if ((surfaceFormatCount == 1) && (vkSurfaceFormatKHRs[0].format == VK_FORMAT_UNDEFINED)) { colorVkFormat = VK_FORMAT_B8G8R8A8_UNORM; } else { // Always select the first available color format // If you need a specific format (e.g. SRGB) you'd need to // iterate over the list of available surface format and // check for it's presence colorVkFormat = vkSurfaceFormatKHRs[0].format; } VkColorSpaceKHR vkColorSpaceKHR = vkSurfaceFormatKHRs[0].colorSpace; // Get the width and height of the given native window and ensure they are never ever zero // -> See "getSafeWidthAndHeight()"-method comments for details uint32_t width = 1; uint32_t height = 1; #ifdef _WIN32 { // Get the client rectangle of the given native window RECT rect; ::GetClientRect(reinterpret_cast<HWND>(nativeWindowHandle), &rect); // Get the width and height... width = static_cast<uint32_t>(rect.right - rect.left); height = static_cast<uint32_t>(rect.bottom - rect.top); // ... and ensure that none of them is ever zero if (width < 1) { width = 1; } if (height < 1) { height = 1; } } #endif // TODO(co) Move the rest into a method VkSwapchainKHR oldVkSwapchainKHR = mVkSwapchainKHR; // Get physical device surface properties and formats VkSurfaceCapabilitiesKHR vkSurfaceCapabilitiesKHR; vkResult = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vkPhysicalDevice, mVkSurfaceKHR, &vkSurfaceCapabilitiesKHR); // assert(!vkResult); // Get available present modes uint32_t presentModeCount = 0; vkResult = vkGetPhysicalDeviceSurfacePresentModesKHR(vkPhysicalDevice, mVkSurfaceKHR, &presentModeCount, nullptr); // assert(!vkResult); // assert(presentModeCount > 0); std::vector<VkPresentModeKHR> vkPresentModeKHRs(presentModeCount); vkResult = vkGetPhysicalDeviceSurfacePresentModesKHR(vkPhysicalDevice, mVkSurfaceKHR, &presentModeCount, vkPresentModeKHRs.data()); // assert(!vkResult); // Width and height are either both -1, or both not -1. VkExtent2D swapchainExtent = {}; if (vkSurfaceCapabilitiesKHR.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 = vkSurfaceCapabilitiesKHR.currentExtent; width = vkSurfaceCapabilitiesKHR.currentExtent.width; height = vkSurfaceCapabilitiesKHR.currentExtent.height; } // Prefer mailbox mode if present, it's the lowest latency non-tearing present mode VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; for (size_t i = 0; i < presentModeCount; ++i) { if (vkPresentModeKHRs[i] == VK_PRESENT_MODE_MAILBOX_KHR) { swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR; break; } if ((swapchainPresentMode != VK_PRESENT_MODE_MAILBOX_KHR) && (vkPresentModeKHRs[i] == VK_PRESENT_MODE_IMMEDIATE_KHR)) { swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; } } // Determine the number of images uint32_t desiredNumberOfSwapchainImages = vkSurfaceCapabilitiesKHR.minImageCount + 1; if ((vkSurfaceCapabilitiesKHR.maxImageCount > 0) && (desiredNumberOfSwapchainImages > vkSurfaceCapabilitiesKHR.maxImageCount)) { desiredNumberOfSwapchainImages = vkSurfaceCapabilitiesKHR.maxImageCount; } VkSurfaceTransformFlagsKHR vkSurfaceTransformFlagsKHR; if (vkSurfaceCapabilitiesKHR.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) { vkSurfaceTransformFlagsKHR = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; } else { vkSurfaceTransformFlagsKHR = vkSurfaceCapabilitiesKHR.currentTransform; } VkSwapchainCreateInfoKHR vkSwapchainCreateInfoKHR = {}; vkSwapchainCreateInfoKHR.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; vkSwapchainCreateInfoKHR.surface = mVkSurfaceKHR; vkSwapchainCreateInfoKHR.minImageCount = desiredNumberOfSwapchainImages; vkSwapchainCreateInfoKHR.imageFormat = colorVkFormat; vkSwapchainCreateInfoKHR.imageColorSpace = vkColorSpaceKHR; vkSwapchainCreateInfoKHR.imageExtent = { swapchainExtent.width, swapchainExtent.height }; vkSwapchainCreateInfoKHR.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; vkSwapchainCreateInfoKHR.preTransform = static_cast<VkSurfaceTransformFlagBitsKHR>(vkSurfaceTransformFlagsKHR); vkSwapchainCreateInfoKHR.imageArrayLayers = 1; vkSwapchainCreateInfoKHR.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; vkSwapchainCreateInfoKHR.presentMode = swapchainPresentMode; vkSwapchainCreateInfoKHR.oldSwapchain = oldVkSwapchainKHR; vkSwapchainCreateInfoKHR.clipped = true; vkSwapchainCreateInfoKHR.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; vkResult = vkCreateSwapchainKHR(vkDevice, &vkSwapchainCreateInfoKHR, nullptr, &mVkSwapchainKHR); // assert(!vkResult); // If an existing swap chain is re-created, destroy the old swap chain // This also cleans up all the presentable images if (VK_NULL_HANDLE != oldVkSwapchainKHR) { for (uint32_t i = 0; i < mSwapchainImageCount; ++i) { vkDestroyImageView(vkDevice, mSwapChainBuffer[i].view, nullptr); } vkDestroySwapchainKHR(vkDevice, oldVkSwapchainKHR, nullptr); } vkResult = vkGetSwapchainImagesKHR(vkDevice, mVkSwapchainKHR, &mSwapchainImageCount, nullptr); // assert(!vkResult); // Get the swap chain images mVkImages.resize(mSwapchainImageCount); vkResult = vkGetSwapchainImagesKHR(vkDevice, mVkSwapchainKHR, &mSwapchainImageCount, mVkImages.data()); // assert(!vkResult); // Get the swap chain buffers containing the image and image view mSwapChainBuffer.resize(mSwapchainImageCount); for (uint32_t i = 0; i < mSwapchainImageCount; ++i) { VkImageViewCreateInfo colorAttachmentView = {}; colorAttachmentView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; colorAttachmentView.format = colorVkFormat; 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.levelCount = 1; colorAttachmentView.subresourceRange.layerCount = 1; colorAttachmentView.viewType = VK_IMAGE_VIEW_TYPE_2D; mSwapChainBuffer[i].image = mVkImages[i]; // Transform images from initial (undefined) to present layout Helper::setImageLayout(context.getSetupVkCommandBuffer(), mSwapChainBuffer[i].image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_IMAGE_ASPECT_COLOR_BIT); colorAttachmentView.image = mSwapChainBuffer[i].image; vkResult = vkCreateImageView(vkDevice, &colorAttachmentView, nullptr, &mSwapChainBuffer[i].view); // assert(!vkResult); } }
//============================================================================== // Vulkan初期化 //============================================================================== bool initVulkan(HINSTANCE hinst, HWND wnd) { VkResult result; //================================================== // Vulkanのインスタンス作成 //================================================== VkApplicationInfo applicationInfo = {}; applicationInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; applicationInfo.pApplicationName = APPLICATION_NAME; applicationInfo.pEngineName = APPLICATION_NAME; applicationInfo.apiVersion = VK_MAKE_VERSION(1, 0, 0); std::vector<LPCSTR> enabledExtensionsByInstance = { VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WIN32_SURFACE_EXTENSION_NAME }; VkInstanceCreateInfo instanceCreateInfo = {}; instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; instanceCreateInfo.pNext = nullptr; instanceCreateInfo.pApplicationInfo = &applicationInfo; if(enabledExtensionsByInstance.empty() == false) { instanceCreateInfo.enabledExtensionCount = enabledExtensionsByInstance.size(); instanceCreateInfo.ppEnabledExtensionNames = enabledExtensionsByInstance.data(); } result = vkCreateInstance(&instanceCreateInfo, nullptr, &g_VulkanInstance); checkVulkanError(result, TEXT("Vulkanインスタンス作成失敗")); //================================================== // 物理デバイス(GPUデバイス) //================================================== // 物理デバイス数を獲得 uint32_t gpuCount = 0; vkEnumeratePhysicalDevices(g_VulkanInstance, &gpuCount, nullptr); assert(gpuCount > 0 && TEXT("物理デバイス数の獲得失敗")); // 物理デバイス数を列挙 std::vector<VkPhysicalDevice> physicalDevices(gpuCount); result = vkEnumeratePhysicalDevices(g_VulkanInstance, &gpuCount, physicalDevices.data()); checkVulkanError(result, TEXT("物理デバイスの列挙に失敗しました")); // すべてのGPU情報を格納 g_GPUs.resize(gpuCount); for(uint32_t i = 0; i < gpuCount; ++i) { g_GPUs[i].device = physicalDevices[i]; // 物理デバイスのプロパティ獲得 vkGetPhysicalDeviceProperties(g_GPUs[i].device, &g_GPUs[i].deviceProperties); // 物理デバイスのメモリプロパティ獲得 vkGetPhysicalDeviceMemoryProperties(g_GPUs[i].device, &g_GPUs[i].deviceMemoryProperties); } // ※このサンプルでは最初に列挙されたGPUデバイスを使用する g_currentGPU = g_GPUs[0]; // グラフィックス操作をサポートするキューを検索 uint32_t queueCount; vkGetPhysicalDeviceQueueFamilyProperties(g_currentGPU.device, &queueCount, nullptr); assert(queueCount >= 1 && TEXT("物理デバイスキューの検索失敗")); std::vector<VkQueueFamilyProperties> queueProps; queueProps.resize(queueCount); vkGetPhysicalDeviceQueueFamilyProperties(g_currentGPU.device, &queueCount, queueProps.data()); uint32_t graphicsQueueIndex = 0; for(graphicsQueueIndex = 0; graphicsQueueIndex < queueCount; ++graphicsQueueIndex) { if(queueProps[graphicsQueueIndex].queueFlags & VK_QUEUE_GRAPHICS_BIT) { break; } } assert(graphicsQueueIndex < queueCount && TEXT("グラフィックスをサポートするキューを見つけられませんでした")); //================================================== // Vulkanデバイス作成 //================================================== float queuePrioritie = 0.0f; VkDeviceQueueCreateInfo queueCreateInfo = {}; queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queueCreateInfo.queueFamilyIndex = graphicsQueueIndex; queueCreateInfo.queueCount = 1; queueCreateInfo.pQueuePriorities = &queuePrioritie; std::vector<LPCSTR> enabledExtensionsByDevice = { VK_KHR_SWAPCHAIN_EXTENSION_NAME }; VkDeviceCreateInfo deviceCreateInfo = {}; deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; deviceCreateInfo.pNext = nullptr; deviceCreateInfo.queueCreateInfoCount = 1; deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo; deviceCreateInfo.pEnabledFeatures = nullptr; if(enabledExtensionsByDevice.empty() == false) { deviceCreateInfo.enabledExtensionCount = enabledExtensionsByDevice.size(); deviceCreateInfo.ppEnabledExtensionNames = enabledExtensionsByDevice.data(); } result = vkCreateDevice(g_currentGPU.device, &deviceCreateInfo, nullptr, &g_VulkanDevice); checkVulkanError(result, TEXT("Vulkanデバイス作成失敗")); // グラフィックスキュー獲得 vkGetDeviceQueue(g_VulkanDevice, graphicsQueueIndex, 0, &g_VulkanQueue); //================================================== // フェンスオブジェクト作成 //================================================== VkFenceCreateInfo fenceCreateInfo = {}; fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fenceCreateInfo.pNext = nullptr; fenceCreateInfo.flags = 0; result = vkCreateFence(g_VulkanDevice, &fenceCreateInfo, nullptr, &g_VulkanFence); checkVulkanError(result, TEXT("フェンスオブジェクト作成失敗")); //================================================== // 同期(セマフォ)オブジェクト作成 //================================================== VkSemaphoreCreateInfo semaphoreCreateInfo = {}; semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; semaphoreCreateInfo.pNext = nullptr; semaphoreCreateInfo.flags = 0; // コマンドバッファ実行用セマフォ作成 result = vkCreateSemaphore(g_VulkanDevice, &semaphoreCreateInfo, nullptr, &g_VulkanSemahoreRenderComplete); checkVulkanError(result, TEXT("コマンドバッファ実行用セマフォ作成失敗")); //================================================== // コマンドプール作製 //================================================== VkCommandPoolCreateInfo cmdPoolInfo = {}; cmdPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; cmdPoolInfo.queueFamilyIndex = 0; cmdPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; result = vkCreateCommandPool(g_VulkanDevice, &cmdPoolInfo, nullptr, &g_VulkanCommandPool); checkVulkanError(result, TEXT("コマンドプール作成失敗")); //================================================== // コマンドバッファ作成 //================================================== // メモリを確保. g_commandBuffers.resize(SWAP_CHAIN_COUNT); VkCommandBufferAllocateInfo commandBufferAllocateInfo = {}; commandBufferAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; commandBufferAllocateInfo.pNext = nullptr; commandBufferAllocateInfo.commandPool = g_VulkanCommandPool; commandBufferAllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; commandBufferAllocateInfo.commandBufferCount = SWAP_CHAIN_COUNT; result = vkAllocateCommandBuffers(g_VulkanDevice, &commandBufferAllocateInfo, g_commandBuffers.data()); checkVulkanError(result, TEXT("コマンドバッファ作成失敗")); //================================================== // OS(今回はWin32)用のサーフェスを作成する //================================================== VkWin32SurfaceCreateInfoKHR surfaceCreateInfo = {}; surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; surfaceCreateInfo.hinstance = hinst; surfaceCreateInfo.hwnd = wnd; result = vkCreateWin32SurfaceKHR(g_VulkanInstance, &surfaceCreateInfo, nullptr, &g_VulkanSurface); checkVulkanError(result, TEXT("サーフェス作成失敗")); //================================================== // スワップチェーンを作成する //================================================== VkFormat imageFormat = VK_FORMAT_R8G8B8A8_UNORM; VkColorSpaceKHR imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; uint32_t surfaceFormatCount = 0; result = vkGetPhysicalDeviceSurfaceFormatsKHR(g_currentGPU.device, g_VulkanSurface, &surfaceFormatCount, nullptr); checkVulkanError(result, TEXT("サポートしているカラーフォーマット数の獲得失敗")); std::vector<VkSurfaceFormatKHR> surfaceFormats; surfaceFormats.resize(surfaceFormatCount); result = vkGetPhysicalDeviceSurfaceFormatsKHR(g_currentGPU.device, g_VulkanSurface, &surfaceFormatCount, surfaceFormats.data()); checkVulkanError(result, TEXT("サポートしているカラーフォーマットの獲得失敗")); // 一致するカラーフォーマットを検索する bool isFind = false; for(const auto& surfaceFormat : surfaceFormats) { if(imageFormat == surfaceFormat.format && imageColorSpace == surfaceFormat.colorSpace) { isFind = true; break; } } if(isFind == false) { imageFormat = surfaceFormats[0].format; imageColorSpace = surfaceFormats[0].colorSpace; } // サーフェスの機能を獲得する VkSurfaceCapabilitiesKHR surfaceCapabilities; VkSurfaceTransformFlagBitsKHR surfaceTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR( g_currentGPU.device, g_VulkanSurface, &surfaceCapabilities); checkVulkanError(result, TEXT("サーフェスの機能の獲得失敗")); if((surfaceCapabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) == 0) { surfaceTransform = surfaceCapabilities.currentTransform; } // プレゼント機能を獲得する VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR; uint32_t presentModeCount; result = vkGetPhysicalDeviceSurfacePresentModesKHR( g_currentGPU.device, g_VulkanSurface, &presentModeCount, nullptr); checkVulkanError(result, TEXT("プレゼント機能数の獲得失敗")); std::vector<VkPresentModeKHR> presentModes; presentModes.resize(presentModeCount); result = vkGetPhysicalDeviceSurfacePresentModesKHR( g_currentGPU.device, g_VulkanSurface, &presentModeCount, presentModes.data()); checkVulkanError(result, TEXT("プレゼント機能の獲得失敗")); for(const auto& presentModeInfo : presentModes) { if(presentModeInfo == VK_PRESENT_MODE_MAILBOX_KHR) { presentMode = VK_PRESENT_MODE_MAILBOX_KHR; break; } if(presentModeInfo == VK_PRESENT_MODE_IMMEDIATE_KHR) { presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; } } presentModes.clear(); uint32_t desiredSwapChainImageCount = surfaceCapabilities.minImageCount + 1; if(surfaceCapabilities.maxImageCount > 0 && desiredSwapChainImageCount > surfaceCapabilities.maxImageCount) { desiredSwapChainImageCount = surfaceCapabilities.maxImageCount; } // スワップチェーン作成 VkSwapchainCreateInfoKHR swapchainCreateInfo = {}; swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; swapchainCreateInfo.pNext = nullptr; swapchainCreateInfo.flags = 0; swapchainCreateInfo.surface = g_VulkanSurface; swapchainCreateInfo.minImageCount = desiredSwapChainImageCount; swapchainCreateInfo.imageFormat = imageFormat; swapchainCreateInfo.imageColorSpace = imageColorSpace; swapchainCreateInfo.imageExtent = { SCREEN_WIDTH, SCREEN_HEIGHT }; swapchainCreateInfo.imageArrayLayers = 1; swapchainCreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; swapchainCreateInfo.queueFamilyIndexCount = 0; swapchainCreateInfo.pQueueFamilyIndices = nullptr; swapchainCreateInfo.preTransform = surfaceTransform; swapchainCreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; swapchainCreateInfo.presentMode = presentMode; swapchainCreateInfo.clipped = VK_TRUE; swapchainCreateInfo.oldSwapchain = VK_NULL_HANDLE; result = vkCreateSwapchainKHR(g_VulkanDevice, &swapchainCreateInfo, nullptr, &g_VulkanSwapChain); checkVulkanError(result, TEXT("サーフェス作成失敗")); //================================================== // イメージの作成 //================================================== uint32_t swapChainCount = 0; result = vkGetSwapchainImagesKHR(g_VulkanDevice, g_VulkanSwapChain, &swapChainCount, nullptr); checkVulkanError(result, TEXT("スワップチェーンイメージ数の獲得失敗")); g_backBuffersTextures.resize(swapChainCount); std::vector<VkImage> images; images.resize(swapChainCount); result = vkGetSwapchainImagesKHR(g_VulkanDevice, g_VulkanSwapChain, &swapChainCount, images.data()); checkVulkanError(result, TEXT("スワップチェーンイメージの獲得失敗")); for(uint32_t i = 0; i < swapChainCount; ++i) { g_backBuffersTextures[i].image = images[i]; } images.clear(); //================================================== // イメージビューの生成 //================================================== for(auto& backBuffer : g_backBuffersTextures) { VkImageViewCreateInfo imageViewCreateInfo = {}; imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; imageViewCreateInfo.pNext = nullptr; imageViewCreateInfo.flags = 0; imageViewCreateInfo.image = backBuffer.image; imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; imageViewCreateInfo.format = imageFormat; imageViewCreateInfo.components.r = VK_COMPONENT_SWIZZLE_R; imageViewCreateInfo.components.g = VK_COMPONENT_SWIZZLE_G; imageViewCreateInfo.components.b = VK_COMPONENT_SWIZZLE_B; imageViewCreateInfo.components.a = VK_COMPONENT_SWIZZLE_A; imageViewCreateInfo.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; result = vkCreateImageView(g_VulkanDevice, &imageViewCreateInfo, nullptr, &backBuffer.view); checkVulkanError(result, TEXT("イメージビューの作成失敗")); setImageLayout( g_VulkanDevice, g_commandBuffers[g_currentBufferIndex], backBuffer.image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); } //================================================== // 深度ステンシルバッファの生成 //================================================== VkFormat depthFormat = VK_FORMAT_D24_UNORM_S8_UINT; VkImageTiling imageTiling; VkFormatProperties formatProperties; vkGetPhysicalDeviceFormatProperties(g_currentGPU.device, depthFormat, &formatProperties); if(formatProperties.linearTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) { imageTiling = VK_IMAGE_TILING_LINEAR; } else if(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) { imageTiling = VK_IMAGE_TILING_OPTIMAL; } else { checkVulkanError(VK_RESULT_MAX_ENUM, TEXT("サポートされていないフォーマットです")); return false; } VkImageCreateInfo imageCreateInfo = {}; imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; imageCreateInfo.pNext = nullptr; imageCreateInfo.flags = 0; imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; imageCreateInfo.format = depthFormat; imageCreateInfo.extent.width = SCREEN_WIDTH; imageCreateInfo.extent.height = SCREEN_HEIGHT; imageCreateInfo.extent.depth = 1; imageCreateInfo.mipLevels = 1; imageCreateInfo.arrayLayers = 1; imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; imageCreateInfo.tiling = imageTiling; imageCreateInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; imageCreateInfo.queueFamilyIndexCount = 0; imageCreateInfo.pQueueFamilyIndices = nullptr; imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; result = vkCreateImage(g_VulkanDevice, &imageCreateInfo, nullptr, &g_depthBufferTexture.image); checkVulkanError(result, TEXT("深度テクスチャ用イメージビュー作成失敗")); // メモリ要件を獲得 VkMemoryRequirements memoryRequirements; vkGetImageMemoryRequirements(g_VulkanDevice, g_depthBufferTexture.image, &memoryRequirements); VkFlags requirementsMask = 0; uint32_t typeBits = memoryRequirements.memoryTypeBits; uint32_t typeIndex = 0; for(const auto& memoryType : g_currentGPU.deviceMemoryProperties.memoryTypes) { if((typeBits & 0x1) == 1) { if((memoryType.propertyFlags & requirementsMask) == requirementsMask) { break; } } typeBits >>= 1; ++typeIndex; } // メモリ確保 VkMemoryAllocateInfo allocInfo = {}; allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocInfo.pNext = nullptr; allocInfo.allocationSize = memoryRequirements.size; allocInfo.memoryTypeIndex = typeIndex; result = vkAllocateMemory(g_VulkanDevice, &allocInfo, nullptr, &g_depthBufferTexture.memory); checkVulkanError(result, TEXT("深度テクスチャ用メモリ確保失敗")); result = vkBindImageMemory(g_VulkanDevice, g_depthBufferTexture.image, g_depthBufferTexture.memory, 0); checkVulkanError(result, TEXT("深度テクスチャメモリにバインド失敗")); VkImageViewCreateInfo imageViewCreateInfo = {}; imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; imageViewCreateInfo.pNext = nullptr; imageViewCreateInfo.image = g_depthBufferTexture.image; imageViewCreateInfo.format = depthFormat; imageViewCreateInfo.components.r = VK_COMPONENT_SWIZZLE_R; imageViewCreateInfo.components.g = VK_COMPONENT_SWIZZLE_G; imageViewCreateInfo.components.b = VK_COMPONENT_SWIZZLE_B; imageViewCreateInfo.components.a = VK_COMPONENT_SWIZZLE_A; imageViewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; imageViewCreateInfo.subresourceRange.baseMipLevel = 0; imageViewCreateInfo.subresourceRange.levelCount = 1; imageViewCreateInfo.subresourceRange.baseArrayLayer = 0; imageViewCreateInfo.subresourceRange.layerCount = 1; imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; imageViewCreateInfo.flags = 0; result = vkCreateImageView(g_VulkanDevice, &imageViewCreateInfo, nullptr, &g_depthBufferTexture.view); checkVulkanError(result, TEXT("深度テクスチャイメージビュー作成失敗")); setImageLayout( g_VulkanDevice, g_commandBuffers[g_currentBufferIndex], g_depthBufferTexture.image, VK_IMAGE_ASPECT_DEPTH_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); //================================================== // フレームバッファの生成 //================================================== VkImageView attachments[2]; // 0=カラーバッファ、1=深度バッファ VkFramebufferCreateInfo frameBufferCreateInfo = {}; frameBufferCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; frameBufferCreateInfo.pNext = nullptr; frameBufferCreateInfo.flags = 0; frameBufferCreateInfo.renderPass = VK_NULL_HANDLE; frameBufferCreateInfo.attachmentCount = 2; frameBufferCreateInfo.pAttachments = attachments; frameBufferCreateInfo.width = SCREEN_WIDTH; frameBufferCreateInfo.height = SCREEN_HEIGHT; frameBufferCreateInfo.layers = 1; g_frameBuffers.resize(SWAP_CHAIN_COUNT); for(uint32_t i = 0; i < SWAP_CHAIN_COUNT; ++i) { attachments[0] = g_backBuffersTextures[i].view; attachments[1] = g_depthBufferTexture.view; auto result = vkCreateFramebuffer(g_VulkanDevice, &frameBufferCreateInfo, nullptr, &g_frameBuffers[i]); checkVulkanError(result, TEXT("フレームバッファ作成失敗")); } return true; }
bool VulkanContext::InitSwapchain() { VkResult res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_devices_[physical_device_], surface_, &surfCapabilities_); assert(res == VK_SUCCESS); uint32_t presentModeCount; res = vkGetPhysicalDeviceSurfacePresentModesKHR(physical_devices_[physical_device_], surface_, &presentModeCount, nullptr); assert(res == VK_SUCCESS); VkPresentModeKHR *presentModes = new VkPresentModeKHR[presentModeCount]; assert(presentModes); res = vkGetPhysicalDeviceSurfacePresentModesKHR(physical_devices_[physical_device_], surface_, &presentModeCount, presentModes); assert(res == VK_SUCCESS); VkExtent2D swapChainExtent; // width and height are either both -1, or both not -1. if (surfCapabilities_.currentExtent.width == (uint32_t)-1) { // If the surface size is undefined, the size is set to // the size of the images requested. ILOG("initSwapchain: %dx%d", width_, height_); swapChainExtent.width = width_; swapChainExtent.height = height_; } else { // If the surface size is defined, the swap chain size must match swapChainExtent = surfCapabilities_.currentExtent; } // TODO: Find a better way to specify the prioritized present mode while being able // to fall back in a sensible way. VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_MAX_ENUM_KHR; for (size_t i = 0; i < presentModeCount; i++) { ILOG("Supported present mode: %d (%s)", presentModes[i], PresentModeString(presentModes[i])); } for (size_t i = 0; i < presentModeCount; i++) { if (swapchainPresentMode == VK_PRESENT_MODE_MAX_ENUM_KHR) { // Default to the first present mode from the list. swapchainPresentMode = presentModes[i]; } if ((flags_ & VULKAN_FLAG_PRESENT_MAILBOX) && presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR; break; } if ((flags_ & VULKAN_FLAG_PRESENT_FIFO_RELAXED) && presentModes[i] == VK_PRESENT_MODE_FIFO_RELAXED_KHR) { swapchainPresentMode = VK_PRESENT_MODE_FIFO_RELAXED_KHR; break; } if ((flags_ & VULKAN_FLAG_PRESENT_IMMEDIATE) && presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) { swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; break; } } #ifdef __ANDROID__ // HACK swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; #endif ILOG("Chosen present mode: %d (%s)", swapchainPresentMode, PresentModeString(swapchainPresentMode)); delete[] presentModes; // Determine the number of VkImage's to use in the swap chain (we desire to // own only 1 image at a time, besides the images being displayed and // queued for display): uint32_t desiredNumberOfSwapChainImages = surfCapabilities_.minImageCount + 1; ILOG("numSwapChainImages: %d", desiredNumberOfSwapChainImages); if ((surfCapabilities_.maxImageCount > 0) && (desiredNumberOfSwapChainImages > surfCapabilities_.maxImageCount)) { // Application must settle for fewer images than desired: desiredNumberOfSwapChainImages = surfCapabilities_.maxImageCount; } VkSurfaceTransformFlagBitsKHR preTransform; if (surfCapabilities_.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) { preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; } else { preTransform = surfCapabilities_.currentTransform; } VkSwapchainCreateInfoKHR swap_chain_info = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR }; swap_chain_info.surface = surface_; swap_chain_info.minImageCount = desiredNumberOfSwapChainImages; swap_chain_info.imageFormat = swapchainFormat_; swap_chain_info.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; swap_chain_info.imageExtent.width = swapChainExtent.width; swap_chain_info.imageExtent.height = swapChainExtent.height; swap_chain_info.preTransform = preTransform; swap_chain_info.imageArrayLayers = 1; swap_chain_info.presentMode = swapchainPresentMode; swap_chain_info.oldSwapchain = VK_NULL_HANDLE; swap_chain_info.clipped = true; swap_chain_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; if (surfCapabilities_.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) swap_chain_info.imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; #ifndef ANDROID // We don't support screenshots on Android // Add more usage flags if they're supported. if (surfCapabilities_.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) swap_chain_info.imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; #endif swap_chain_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; swap_chain_info.queueFamilyIndexCount = 0; swap_chain_info.pQueueFamilyIndices = NULL; // OPAQUE is not supported everywhere. if (surfCapabilities_.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) { swap_chain_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; } else { // This should be supported anywhere, and is the only thing supported on the SHIELD TV, for example. swap_chain_info.compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; } res = vkCreateSwapchainKHR(device_, &swap_chain_info, NULL, &swapchain_); if (res != VK_SUCCESS) { ELOG("vkCreateSwapchainKHR failed!"); return false; } return true; }
/** * * @ThreadSafe */ ISwapchainSP VKTS_APIENTRY wsiSwapchainCreate(const VkPhysicalDevice physicalDevice, const VkDevice device, const VkSwapchainCreateFlagsKHR flags, const VkSurfaceKHR surface, const uint32_t minImageCount, const uint32_t imageArrayLayers, const VkImageUsageFlags imageUsage, const VkSharingMode imageSharingMode, const uint32_t queueFamilyIndexCount, const uint32_t* queueFamilyIndices, const VkCompositeAlphaFlagBitsKHR compositeAlpha, const VkBool32 clipped, const VkSwapchainKHR oldSwapchain) { if (!physicalDevice || !device) { return ISwapchainSP(); } VkResult result; // VkSurfaceCapabilitiesKHR surfaceCapabilities; result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &surfaceCapabilities); if (result != VK_SUCCESS) { vkts::logPrint(VKTS_LOG_ERROR, "Wsi: Could not get surface properties."); return ISwapchainSP(); } VkSurfaceTransformFlagBitsKHR preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; if (!(surfaceCapabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)) { preTransform = surfaceCapabilities.currentTransform; } uint32_t surfacePresentModesCount; result = vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &surfacePresentModesCount, nullptr); if (result != VK_SUCCESS) { vkts::logPrint(VKTS_LOG_ERROR, "Wsi: Could not get surface present mode count."); return ISwapchainSP(); } std::unique_ptr<VkPresentModeKHR[]> surfacePresentModes = std::unique_ptr<VkPresentModeKHR[]> (new VkPresentModeKHR[surfacePresentModesCount]); if (!surfacePresentModes.get()) { vkts::logPrint(VKTS_LOG_ERROR, "Wsi: Could not create surface present modes."); return ISwapchainSP(); } result = vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &surfacePresentModesCount, &surfacePresentModes[0]); if (result != VK_SUCCESS) { vkts::logPrint(VKTS_LOG_ERROR, "Wsi: Could not get surface present modes."); return ISwapchainSP(); } // Regarding specification, this present mode has to be supported. VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR; uint32_t surfaceFormatsCount; result = vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &surfaceFormatsCount, nullptr); if (result != VK_SUCCESS || surfaceFormatsCount == 0) { vkts::logPrint(VKTS_LOG_ERROR, "Wsi: Could not get surface formats count."); return ISwapchainSP(); } std::unique_ptr<VkSurfaceFormatKHR[]> surfaceFormats = std::unique_ptr <VkSurfaceFormatKHR[]>(new VkSurfaceFormatKHR[surfaceFormatsCount]); if (!surfaceFormats.get()) { vkts::logPrint(VKTS_LOG_ERROR, "Wsi: Could not create surface formats."); return ISwapchainSP(); } result = vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &surfaceFormatsCount, &surfaceFormats[0]); if (result != VK_SUCCESS) { vkts::logPrint(VKTS_LOG_ERROR, "Wsi: Could not get surface formats."); return ISwapchainSP(); } VkFormat imageFormat = surfaceFormats[0].format; VkColorSpaceKHR imageColorSpace = surfaceFormats[0].colorSpace; VkSwapchainCreateInfoKHR swapchainCreateInfo; memset(&swapchainCreateInfo, 0, sizeof(VkSwapchainCreateInfoKHR)); swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; swapchainCreateInfo.flags = flags; swapchainCreateInfo.surface = surface; swapchainCreateInfo.minImageCount = minImageCount; swapchainCreateInfo.imageFormat = imageFormat; swapchainCreateInfo.imageColorSpace = imageColorSpace; swapchainCreateInfo.imageExtent = surfaceCapabilities.currentExtent; swapchainCreateInfo.imageArrayLayers = imageArrayLayers; swapchainCreateInfo.imageUsage = imageUsage; swapchainCreateInfo.imageSharingMode = imageSharingMode; swapchainCreateInfo.queueFamilyIndexCount = queueFamilyIndexCount; swapchainCreateInfo.pQueueFamilyIndices = queueFamilyIndices; swapchainCreateInfo.preTransform = preTransform; swapchainCreateInfo.compositeAlpha = compositeAlpha; swapchainCreateInfo.presentMode = presentMode; swapchainCreateInfo.clipped = clipped; swapchainCreateInfo.oldSwapchain = oldSwapchain; VkSwapchainKHR swapchain; result = vkCreateSwapchainKHR(device, &swapchainCreateInfo, nullptr, &swapchain); if (result != VK_SUCCESS) { logPrint(VKTS_LOG_ERROR, "Wsi: Could not create swapchain."); return ISwapchainSP(); } auto newInstance = new Swapchain(device, flags, surface, minImageCount, imageFormat, imageColorSpace, surfaceCapabilities.currentExtent, imageArrayLayers, imageUsage, imageSharingMode, queueFamilyIndexCount, queueFamilyIndices, preTransform, compositeAlpha, presentMode, clipped, oldSwapchain, swapchain); if (!newInstance) { vkDestroySwapchainKHR(device, swapchain, nullptr); return ISwapchainSP(); } return ISwapchainSP(newInstance); }
int main(int argc, char *argv[]) { VkResult U_ASSERT_ONLY res; struct sample_info info = {}; char sample_title[] = "Swapchain Initialization Sample"; /* * Set up swapchain: * - Get supported uses for all queues * - Try to find a queue that supports both graphics and present * - If no queue supports both, find a present queue and make sure we have a * graphics queue * - Get a list of supported formats and use the first one * - Get surface properties and present modes and use them to create a swap * chain * - Create swap chain buffers * - For each buffer, create a color attachment view and set its layout to * color attachment */ init_global_layer_properties(info); init_instance_extension_names(info); init_device_extension_names(info); init_instance(info, sample_title); init_enumerate_device(info); init_connection(info); init_window_size(info, 50, 50); init_window(info); /* VULKAN_KEY_START */ // Construct the surface description: #ifdef _WIN32 VkWin32SurfaceCreateInfoKHR createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; createInfo.pNext = NULL; createInfo.hinstance = info.connection; createInfo.hwnd = info.window; res = vkCreateWin32SurfaceKHR(info.inst, &createInfo, NULL, &info.surface); #else // _WIN32 VkXcbSurfaceCreateInfoKHR createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; createInfo.pNext = NULL; createInfo.connection = info.connection; createInfo.window = info.window; res = vkCreateXcbSurfaceKHR(info.inst, &createInfo, NULL, &info.surface); #endif // _WIN32 assert(res == VK_SUCCESS); // Iterate over each queue to learn whether it supports presenting: VkBool32 *supportsPresent = (VkBool32 *)malloc(info.queue_count * sizeof(VkBool32)); for (uint32_t i = 0; i < info.queue_count; i++) { vkGetPhysicalDeviceSurfaceSupportKHR(info.gpus[0], i, info.surface, &supportsPresent[i]); } // Search for a graphics queue and a present queue in the array of queue // families, try to find one that supports both uint32_t graphicsQueueNodeIndex = UINT32_MAX; for (uint32_t i = 0; i < info.queue_count; i++) { if ((info.queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) { if (supportsPresent[i] == VK_TRUE) { graphicsQueueNodeIndex = i; break; } } } free(supportsPresent); // Generate error if could not find a queue that supports both a graphics // and present if (graphicsQueueNodeIndex == UINT32_MAX) { std::cout << "Could not find a queue that supports both graphics and " "present\n"; exit(-1); } info.graphics_queue_family_index = graphicsQueueNodeIndex; init_device(info); // Get the list of VkFormats that are supported: uint32_t formatCount; res = vkGetPhysicalDeviceSurfaceFormatsKHR(info.gpus[0], info.surface, &formatCount, NULL); assert(res == VK_SUCCESS); VkSurfaceFormatKHR *surfFormats = (VkSurfaceFormatKHR *)malloc(formatCount * sizeof(VkSurfaceFormatKHR)); res = vkGetPhysicalDeviceSurfaceFormatsKHR(info.gpus[0], info.surface, &formatCount, surfFormats); assert(res == VK_SUCCESS); // 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 (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED) { info.format = VK_FORMAT_B8G8R8A8_UNORM; } else { assert(formatCount >= 1); info.format = surfFormats[0].format; } VkSurfaceCapabilitiesKHR surfCapabilities; res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(info.gpus[0], info.surface, &surfCapabilities); assert(res == VK_SUCCESS); uint32_t presentModeCount; res = vkGetPhysicalDeviceSurfacePresentModesKHR(info.gpus[0], info.surface, &presentModeCount, NULL); assert(res == VK_SUCCESS); VkPresentModeKHR *presentModes = (VkPresentModeKHR *)malloc(presentModeCount * sizeof(VkPresentModeKHR)); res = vkGetPhysicalDeviceSurfacePresentModesKHR( info.gpus[0], info.surface, &presentModeCount, presentModes); assert(res == VK_SUCCESS); VkExtent2D swapChainExtent; // width and height are either both -1, or both not -1. if (surfCapabilities.currentExtent.width == (uint32_t)-1) { // If the surface size is undefined, the size is set to // the size of the images requested. swapChainExtent.width = info.width; swapChainExtent.height = info.height; } else { // If the surface size is defined, the swap chain size must match swapChainExtent = surfCapabilities.currentExtent; } // If mailbox mode is available, use it, as is the lowest-latency non- // tearing mode. If not, try IMMEDIATE which will usually be available, // and is fastest (though it tears). If not, fall back to FIFO which is // always available. VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; for (size_t i = 0; i < presentModeCount; i++) { if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR; break; } if ((swapchainPresentMode != VK_PRESENT_MODE_MAILBOX_KHR) && (presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR)) { swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; } } // Determine the number of VkImage's to use in the swap chain (we desire to // own only 1 image at a time, besides the images being displayed and // queued for display): uint32_t desiredNumberOfSwapChainImages = surfCapabilities.minImageCount + 1; if ((surfCapabilities.maxImageCount > 0) && (desiredNumberOfSwapChainImages > surfCapabilities.maxImageCount)) { // Application must settle for fewer images than desired: desiredNumberOfSwapChainImages = surfCapabilities.maxImageCount; } VkSurfaceTransformFlagBitsKHR preTransform; if (surfCapabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) { preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; } else { preTransform = surfCapabilities.currentTransform; } VkSwapchainCreateInfoKHR swap_chain = {}; swap_chain.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; swap_chain.pNext = NULL; swap_chain.surface = info.surface; swap_chain.minImageCount = desiredNumberOfSwapChainImages; swap_chain.imageFormat = info.format; swap_chain.imageExtent.width = swapChainExtent.width; swap_chain.imageExtent.height = swapChainExtent.height; swap_chain.preTransform = preTransform; swap_chain.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; swap_chain.imageArrayLayers = 1; swap_chain.presentMode = swapchainPresentMode; swap_chain.oldSwapchain = NULL; swap_chain.clipped = true; swap_chain.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; swap_chain.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; swap_chain.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; swap_chain.queueFamilyIndexCount = 0; swap_chain.pQueueFamilyIndices = NULL; res = vkCreateSwapchainKHR(info.device, &swap_chain, NULL, &info.swap_chain); assert(res == VK_SUCCESS); res = vkGetSwapchainImagesKHR(info.device, info.swap_chain, &info.swapchainImageCount, NULL); assert(res == VK_SUCCESS); VkImage *swapchainImages = (VkImage *)malloc(info.swapchainImageCount * sizeof(VkImage)); assert(swapchainImages); res = vkGetSwapchainImagesKHR(info.device, info.swap_chain, &info.swapchainImageCount, swapchainImages); assert(res == VK_SUCCESS); info.buffers.resize(info.swapchainImageCount); // Going to need a command buffer to send the memory barriers in // set_image_layout but we couldn't have created one before we knew // what our graphics_queue_family_index is, but now that we have it, // create the command buffer init_command_pool(info); init_command_buffer(info); execute_begin_command_buffer(info); vkGetDeviceQueue(info.device, info.graphics_queue_family_index, 0, &info.queue); for (uint32_t i = 0; i < info.swapchainImageCount; i++) { VkImageViewCreateInfo color_image_view = {}; color_image_view.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; color_image_view.pNext = NULL; color_image_view.format = info.format; color_image_view.components.r = VK_COMPONENT_SWIZZLE_R; color_image_view.components.g = VK_COMPONENT_SWIZZLE_G; color_image_view.components.b = VK_COMPONENT_SWIZZLE_B; color_image_view.components.a = VK_COMPONENT_SWIZZLE_A; color_image_view.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; color_image_view.subresourceRange.baseMipLevel = 0; color_image_view.subresourceRange.levelCount = 1; color_image_view.subresourceRange.baseArrayLayer = 0; color_image_view.subresourceRange.layerCount = 1; color_image_view.viewType = VK_IMAGE_VIEW_TYPE_2D; color_image_view.flags = 0; info.buffers[i].image = swapchainImages[i]; set_image_layout(info, info.buffers[i].image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); color_image_view.image = info.buffers[i].image; res = vkCreateImageView(info.device, &color_image_view, NULL, &info.buffers[i].view); assert(res == VK_SUCCESS); } free(swapchainImages); execute_end_command_buffer(info); execute_queue_command_buffer(info); /* VULKAN_KEY_END */ /* Clean Up */ VkCommandBuffer cmd_bufs[1] = {info.cmd}; vkFreeCommandBuffers(info.device, info.cmd_pool, 1, cmd_bufs); vkDestroyCommandPool(info.device, info.cmd_pool, NULL); for (uint32_t i = 0; i < info.swapchainImageCount; i++) { vkDestroyImageView(info.device, info.buffers[i].view, NULL); } vkDestroySwapchainKHR(info.device, info.swap_chain, NULL); destroy_device(info); destroy_window(info); destroy_instance(info); return 0; }
void VulkanWindow::InitializeSwapchain() { vkGetPhysicalDeviceSurfaceCapabilitiesKHR ( mVulkanRenderer.GetPhysicalDevice(), mVkSurfaceKHR, &mVkSurfaceCapabilitiesKHR ); uint32_t surface_format_count = 0; vkGetPhysicalDeviceSurfaceFormatsKHR ( mVulkanRenderer.GetPhysicalDevice(), mVkSurfaceKHR, &surface_format_count, nullptr ); if ( surface_format_count == 0 ) { std::ostringstream stream; stream << "Physical device reports no surface formats."; throw std::runtime_error ( stream.str().c_str() ); } VkSurfaceFormatKHR surface_format_khr; std::vector<VkSurfaceFormatKHR> surface_format_list ( surface_format_count ); vkGetPhysicalDeviceSurfaceFormatsKHR ( mVulkanRenderer.GetPhysicalDevice(), mVkSurfaceKHR, &surface_format_count, surface_format_list.data() ); if ( surface_format_list[0].format == VK_FORMAT_UNDEFINED ) { surface_format_khr = mVulkanRenderer.GetSurfaceFormatKHR(); } else { surface_format_khr = surface_format_list[0]; } if ( mSwapchainImageCount < mVkSurfaceCapabilitiesKHR.minImageCount ) { mSwapchainImageCount = mVkSurfaceCapabilitiesKHR.minImageCount; } if ( ( mVkSurfaceCapabilitiesKHR.maxImageCount > 0 ) && ( mSwapchainImageCount > mVkSurfaceCapabilitiesKHR.maxImageCount ) ) { mSwapchainImageCount = mVkSurfaceCapabilitiesKHR.maxImageCount; } VkSwapchainCreateInfoKHR swapchain_create_info{}; swapchain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; swapchain_create_info.surface = mVkSurfaceKHR; swapchain_create_info.minImageCount = mSwapchainImageCount; swapchain_create_info.imageFormat = surface_format_khr.format; swapchain_create_info.imageColorSpace = surface_format_khr.colorSpace; swapchain_create_info.imageExtent.width = mVkSurfaceCapabilitiesKHR.currentExtent.width; swapchain_create_info.imageExtent.height = mVkSurfaceCapabilitiesKHR.currentExtent.height; swapchain_create_info.imageArrayLayers = 1; swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; swapchain_create_info.queueFamilyIndexCount = 0; swapchain_create_info.pQueueFamilyIndices = nullptr; swapchain_create_info.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; swapchain_create_info.presentMode = VK_PRESENT_MODE_FIFO_KHR; // This may be reset below. swapchain_create_info.clipped = VK_TRUE; swapchain_create_info.oldSwapchain = mVkSwapchainKHR; // Used for Resising. { uint32_t present_mode_count = 0; vkGetPhysicalDeviceSurfacePresentModesKHR ( mVulkanRenderer.GetPhysicalDevice(), mVkSurfaceKHR, &present_mode_count, nullptr ); std::vector<VkPresentModeKHR> present_mode_list ( present_mode_count ); vkGetPhysicalDeviceSurfacePresentModesKHR ( mVulkanRenderer.GetPhysicalDevice(), mVkSurfaceKHR, &present_mode_count, present_mode_list.data() ); for ( auto& i : present_mode_list ) { if ( i == VK_PRESENT_MODE_MAILBOX_KHR ) { swapchain_create_info.presentMode = i; break; } } } if ( VkResult result = vkCreateSwapchainKHR ( mVulkanRenderer.GetDevice(), &swapchain_create_info, nullptr, &mVkSwapchainKHR ) ) { std::ostringstream stream; stream << "Call to vkCreateSwapchainKHR failed: ( " << GetVulkanResultString ( result ) << " )"; throw std::runtime_error ( stream.str().c_str() ); } if ( swapchain_create_info.oldSwapchain != VK_NULL_HANDLE ) { vkDestroySwapchainKHR ( mVulkanRenderer.GetDevice(), swapchain_create_info.oldSwapchain, nullptr ); } }