void VulkanWindow::InitializeSurface() { #if defined ( VK_USE_PLATFORM_WIN32_KHR ) VkWin32SurfaceCreateInfoKHR win32_surface_create_info_khr {}; win32_surface_create_info_khr.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; win32_surface_create_info_khr.hwnd = reinterpret_cast<HWND> ( mWindowId ); win32_surface_create_info_khr.hinstance = reinterpret_cast<HINSTANCE> ( GetWindowLongPtr ( win32_surface_create_info_khr.hwnd, GWLP_HINSTANCE ) ); if ( VkResult result = vkCreateWin32SurfaceKHR ( mVulkanRenderer.GetInstance(), &win32_surface_create_info_khr, nullptr, &mVkSurfaceKHR ) ) { std::ostringstream stream; stream << "Call to vkCreateWin32SurfaceKHR failed: ( " << GetVulkanResultString ( result ) << " )"; throw std::runtime_error ( stream.str().c_str() ); } #elif defined( VK_USE_PLATFORM_XLIB_KHR ) VkXlibSurfaceCreateInfoKHR xlib_surface_create_info_khr {}; xlib_surface_create_info_khr.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; xlib_surface_create_info_khr.dpy = XOpenDisplay ( nullptr ); xlib_surface_create_info_khr.window = reinterpret_cast<::Window> ( mWindowId ); if ( VkResult result = vkCreateXlibSurfaceKHR ( mVulkanRenderer.GetInstance(), &xlib_surface_create_info_khr, nullptr, &mVkSurfaceKHR ) ) { std::ostringstream stream; stream << "Call to vkCreateXlibSurfaceKHR failed: ( " << GetVulkanResultString ( result ) << " )"; throw std::runtime_error ( stream.str().c_str() ); } #endif VkBool32 wsi_supported = false; vkGetPhysicalDeviceSurfaceSupportKHR ( mVulkanRenderer.GetPhysicalDevice(), mVulkanRenderer.GetQueueFamilyIndex(), mVkSurfaceKHR, &wsi_supported ); if ( !wsi_supported ) { std::ostringstream stream; stream << "WSI not supported."; throw std::runtime_error ( stream.str().c_str() ); } }
void VulkanWindow::EndRender() const { vkCmdEndRenderPass ( mVulkanRenderer.GetCommandBuffer() ); if ( VkResult result = vkEndCommandBuffer ( mVulkanRenderer.GetCommandBuffer() ) ) { std::cout << GetVulkanResultString ( result ) << " " << __func__ << " " << __LINE__ << " " << std::endl; } VkSubmitInfo submit_info{}; submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit_info.waitSemaphoreCount = 0; submit_info.pWaitSemaphores = nullptr; submit_info.pWaitDstStageMask = nullptr; submit_info.commandBufferCount = 1; submit_info.pCommandBuffers = &mVulkanRenderer.GetCommandBuffer(); submit_info.signalSemaphoreCount = 1; submit_info.pSignalSemaphores = &mVulkanRenderer.GetSignalSemaphore(); if ( VkResult result = vkQueueSubmit ( mVulkanRenderer.GetQueue(), 1, &submit_info, VK_NULL_HANDLE ) ) { std::cout << GetVulkanResultString ( result ) << " " << __func__ << " " << __LINE__ << " " << std::endl; } std::array<VkResult, 1> result_array{ { VkResult::VK_SUCCESS } }; VkPresentInfoKHR present_info{}; present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; present_info.waitSemaphoreCount = 1; present_info.pWaitSemaphores = &mVulkanRenderer.GetSignalSemaphore(); present_info.swapchainCount = 1; present_info.pSwapchains = &mVkSwapchainKHR; present_info.pImageIndices = &mActiveImageIndex; present_info.pResults = result_array.data(); if ( VkResult result = vkQueuePresentKHR ( mVulkanRenderer.GetQueue(), &present_info ) ) { std::cout << GetVulkanResultString ( result ) << " " << __func__ << " " << __LINE__ << " " << std::endl; } }
void VulkanUniformBuffer::InitializeDescriptorSet ( VkDescriptorSet& aVkDescriptorSet, const VkDescriptorSetLayout& aVkDescriptorSetLayout, const VkDescriptorBufferInfo& aVkDescriptorBufferInfo ) { VkDescriptorSetAllocateInfo descriptor_set_allocate_info{}; descriptor_set_allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; descriptor_set_allocate_info.descriptorPool = mVkDescriptorPool; descriptor_set_allocate_info.descriptorSetCount = 1; descriptor_set_allocate_info.pSetLayouts = &aVkDescriptorSetLayout; if ( VkResult result = vkAllocateDescriptorSets ( mVulkanRenderer.GetDevice(), &descriptor_set_allocate_info, &aVkDescriptorSet ) ) { std::ostringstream stream; stream << "Allocate Descriptor Set failed: ( " << GetVulkanResultString ( result ) << " )"; throw std::runtime_error ( stream.str().c_str() ); } VkWriteDescriptorSet write_descriptor_set{}; write_descriptor_set.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; write_descriptor_set.pNext = nullptr; write_descriptor_set.dstSet = aVkDescriptorSet; write_descriptor_set.dstBinding = 0; write_descriptor_set.dstArrayElement = 0; write_descriptor_set.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; write_descriptor_set.descriptorCount = 1; write_descriptor_set.pBufferInfo = &aVkDescriptorBufferInfo; write_descriptor_set.pImageInfo = nullptr; write_descriptor_set.pTexelBufferView = nullptr; vkUpdateDescriptorSets ( mVulkanRenderer.GetDevice(), 1, &write_descriptor_set, 0, nullptr ); }
void VulkanWindow::Finalize() { if ( VkResult result = vkQueueWaitIdle ( mVulkanRenderer.GetQueue() ) ) { std::cerr << "vkQueueWaitIdle failed: " << GetVulkanResultString ( result ); } if ( VkResult result = vkDeviceWaitIdle ( mVulkanRenderer.GetDevice() ) ) { std::cerr << "vkDeviceWaitIdle failed: " << GetVulkanResultString ( result ); } FinalizeFrameBuffers(); FinalizeDepthStencil(); FinalizeImageViews(); FinalizeSwapchain(); FinalizeSurface(); }
void VulkanWindow::InitializeImageViews() { if ( VkResult result = vkGetSwapchainImagesKHR ( mVulkanRenderer.GetDevice(), mVkSwapchainKHR, &mSwapchainImageCount, nullptr ) ) { std::ostringstream stream; stream << "Get swapchain image count failed: ( " << GetVulkanResultString ( result ) << " )"; throw std::runtime_error ( stream.str().c_str() ); } mVkSwapchainImages.resize ( mSwapchainImageCount ); mVkSwapchainImageViews.resize ( mSwapchainImageCount ); if ( VkResult result = vkGetSwapchainImagesKHR ( mVulkanRenderer.GetDevice(), mVkSwapchainKHR, &mSwapchainImageCount, mVkSwapchainImages.data() ) ) { std::ostringstream stream; stream << "Get swapchain images failed: ( " << GetVulkanResultString ( result ) << " )"; throw std::runtime_error ( stream.str().c_str() ); } for ( uint32_t i = 0; i < mSwapchainImageCount; ++i ) { VkImageViewCreateInfo image_view_create_info{}; image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; image_view_create_info.pNext = nullptr; image_view_create_info.flags = 0; image_view_create_info.image = mVkSwapchainImages[i]; image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; image_view_create_info.format = mVulkanRenderer.GetSurfaceFormatKHR().format; image_view_create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; image_view_create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; image_view_create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; image_view_create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; image_view_create_info.subresourceRange.baseMipLevel = 0; image_view_create_info.subresourceRange.levelCount = 1; image_view_create_info.subresourceRange.baseArrayLayer = 0; image_view_create_info.subresourceRange.layerCount = 1; vkCreateImageView ( mVulkanRenderer.GetDevice(), &image_view_create_info, nullptr, &mVkSwapchainImageViews[i] ); } }
void VulkanWindow::OnResizeViewport ( int32_t aX, int32_t aY, uint32_t aWidth, uint32_t aHeight ) { VkSurfaceCapabilitiesKHR surface_capabilities{}; VkResult result {vkGetPhysicalDeviceSurfaceCapabilitiesKHR ( mVulkanRenderer.GetPhysicalDevice(), mVkSurfaceKHR, &surface_capabilities ) }; if ( result == VK_SUCCESS && std::memcmp ( &surface_capabilities, &mVkSurfaceCapabilitiesKHR, sizeof ( VkSurfaceCapabilitiesKHR ) ) != 0 ) { if ( VK_SUCCESS != ( result = vkQueueWaitIdle ( mVulkanRenderer.GetQueue() ) ) ) { std::ostringstream stream; stream << "vkQueueWaitIdle failed: " << GetVulkanResultString ( result ); throw std::runtime_error ( stream.str().c_str() ); } if ( VK_SUCCESS != ( result = vkDeviceWaitIdle ( mVulkanRenderer.GetDevice() ) ) ) { std::ostringstream stream; stream << "vkDeviceWaitIdle failed: " << GetVulkanResultString ( result ); throw std::runtime_error ( stream.str().c_str() ); } FinalizeFrameBuffers(); FinalizeDepthStencil(); FinalizeImageViews(); InitializeSwapchain(); InitializeImageViews(); InitializeDepthStencil(); InitializeFrameBuffers(); } mVkViewport.x = static_cast<float> ( aX ); mVkViewport.y = static_cast<float> ( aY ); mVkViewport.width = static_cast<float> ( aWidth ); mVkViewport.height = static_cast<float> ( aHeight ); // Clip Scissors to surface extents mVkScissor.offset.x = ( aX < 0 ) ? 0 : aX; mVkScissor.offset.y = ( aY < 0 ) ? 0 : aY; mVkScissor.extent.width = ( aX + aWidth > mVkSurfaceCapabilitiesKHR.currentExtent.width ) ? mVkSurfaceCapabilitiesKHR.currentExtent.width : aX + aWidth; mVkScissor.extent.height = ( aY + aHeight > mVkSurfaceCapabilitiesKHR.currentExtent.height ) ? mVkSurfaceCapabilitiesKHR.currentExtent.height : aY + aHeight; }
void VulkanUniformBuffer::InitializeDescriptorPool() { VkDescriptorPoolSize descriptor_pool_size{}; descriptor_pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; descriptor_pool_size.descriptorCount = 1; VkDescriptorPoolCreateInfo descriptor_pool_create_info{}; descriptor_pool_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; descriptor_pool_create_info.pNext = nullptr; descriptor_pool_create_info.flags = 0; descriptor_pool_create_info.maxSets = 1; descriptor_pool_create_info.poolSizeCount = 1; descriptor_pool_create_info.pPoolSizes = &descriptor_pool_size; if ( VkResult result = vkCreateDescriptorPool ( mVulkanRenderer.GetDevice(), &descriptor_pool_create_info, nullptr, &mVkDescriptorPool ) ) { std::ostringstream stream; stream << "vkCreateDescriptorPool failed. error code: ( " << GetVulkanResultString ( result ) << " )"; throw std::runtime_error ( stream.str().c_str() ); } }
VulkanError::VulkanError(VkResult result) : std::runtime_error(GetVulkanResultString(result)) , result(result) { }
void VulkanWindow::BeginRender() const { /** @todo I no longer think writing to the matrix buffer each time is optimal, * but I do not want to introduce a dirty matrix flag. * Will probably just make the set projection and transform to virtual. */ mMatrices.WriteMemory ( 0, sizeof ( float ) * 16, mProjectionMatrix.GetMatrix4x4() ); mMatrices.WriteMemory ( sizeof ( float ) * 16, sizeof ( float ) * 16, mViewMatrix.GetMatrix4x4() ); if ( VkResult result = vkAcquireNextImageKHR ( mVulkanRenderer.GetDevice(), mVkSwapchainKHR, UINT64_MAX, VK_NULL_HANDLE, mVulkanRenderer.GetFence(), const_cast<uint32_t*> ( &mActiveImageIndex ) ) ) { std::cout << GetVulkanResultString ( result ) << " " << __func__ << " " << __LINE__ << " " << std::endl; } if ( VkResult result = vkWaitForFences ( mVulkanRenderer.GetDevice(), 1, &mVulkanRenderer.GetFence(), VK_TRUE, UINT64_MAX ) ) { std::cout << GetVulkanResultString ( result ) << " " << __func__ << " " << __LINE__ << " " << std::endl; } if ( VkResult result = vkResetFences ( mVulkanRenderer.GetDevice(), 1, &mVulkanRenderer.GetFence() ) ) { std::cout << GetVulkanResultString ( result ) << " " << __func__ << " " << __LINE__ << " " << std::endl; } if ( VkResult result = vkQueueWaitIdle ( mVulkanRenderer.GetQueue() ) ) { std::cout << GetVulkanResultString ( result ) << " " << __func__ << " " << __LINE__ << " " << std::endl; } VkCommandBufferBeginInfo command_buffer_begin_info{}; command_buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; command_buffer_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; if ( VkResult result = vkBeginCommandBuffer ( mVulkanRenderer.GetCommandBuffer(), &command_buffer_begin_info ) ) { std::cout << GetVulkanResultString ( result ) << " Error Code: " << result << " at " << __func__ << " line " << __LINE__ << " " << std::endl; } vkCmdSetViewport ( mVulkanRenderer.GetCommandBuffer(), 0, 1, &mVkViewport ); vkCmdSetScissor ( mVulkanRenderer.GetCommandBuffer(), 0, 1, &mVkScissor ); /* [0] is color, [1] is depth/stencil.*/ /**@todo Allow for changing the clear values.*/ std::array<VkClearValue, 2> clear_values{ { { {{0}} }, { {{0}} } } }; clear_values[0].color.float32[0] = 0.5f; clear_values[0].color.float32[1] = 0.5f; clear_values[0].color.float32[2] = 0.5f; clear_values[0].color.float32[3] = 0.0f; clear_values[1].depthStencil.depth = 1.0f; clear_values[1].depthStencil.stencil = 0; VkRenderPassBeginInfo render_pass_begin_info{}; render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; render_pass_begin_info.renderPass = mVulkanRenderer.GetRenderPass(); render_pass_begin_info.framebuffer = mVkFramebuffers[mActiveImageIndex]; render_pass_begin_info.renderArea = mVkScissor; render_pass_begin_info.clearValueCount = static_cast<uint32_t> ( clear_values.size() ); render_pass_begin_info.pClearValues = clear_values.data(); vkCmdBeginRenderPass ( mVulkanRenderer.GetCommandBuffer(), &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE ); }
void VulkanWindow::InitializeDepthStencil() { mHasStencil = ( mVulkanRenderer.GetDepthStencilFormat() == VK_FORMAT_D32_SFLOAT_S8_UINT || mVulkanRenderer.GetDepthStencilFormat() == VK_FORMAT_D24_UNORM_S8_UINT || mVulkanRenderer.GetDepthStencilFormat() == VK_FORMAT_D16_UNORM_S8_UINT ); VkImageCreateInfo image_create_info{}; image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; image_create_info.flags = 0; image_create_info.format = mVulkanRenderer.GetDepthStencilFormat(); image_create_info.imageType = VK_IMAGE_TYPE_2D; image_create_info.extent.width = mVkSurfaceCapabilitiesKHR.currentExtent.width; image_create_info.extent.height = mVkSurfaceCapabilitiesKHR.currentExtent.height; image_create_info.extent.depth = 1; image_create_info.mipLevels = 1; image_create_info.arrayLayers = 1; image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; image_create_info.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; image_create_info.queueFamilyIndexCount = 0; image_create_info.pQueueFamilyIndices = nullptr; image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; if ( VkResult result = vkCreateImage ( mVulkanRenderer.GetDevice(), &image_create_info, nullptr, &mVkDepthStencilImage ) ) { std::ostringstream stream; stream << "Call to vkCreateImage failed: ( " << GetVulkanResultString ( result ) << " )"; throw std::runtime_error ( stream.str().c_str() ); } VkMemoryRequirements memory_requirements; vkGetImageMemoryRequirements ( mVulkanRenderer.GetDevice(), mVkDepthStencilImage, &memory_requirements ); auto required_bits = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; uint32_t memory_index = UINT32_MAX; for ( uint32_t i = 0; i < mVulkanRenderer.GetPhysicalDeviceMemoryProperties().memoryTypeCount; ++i ) { if ( memory_requirements.memoryTypeBits & ( 1 << i ) ) { if ( ( mVulkanRenderer.GetPhysicalDeviceMemoryProperties().memoryTypes[i].propertyFlags & required_bits ) == required_bits ) { memory_index = i; break; } } } if ( memory_index == UINT32_MAX ) { std::ostringstream stream; stream << "Could not find a suitable memory index."; throw std::runtime_error ( stream.str().c_str() ); } VkMemoryAllocateInfo memory_allocate_info{}; memory_allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; memory_allocate_info.allocationSize = memory_requirements.size; memory_allocate_info.memoryTypeIndex = memory_index; vkAllocateMemory ( mVulkanRenderer.GetDevice(), &memory_allocate_info, nullptr, &mVkDepthStencilImageMemory ); vkBindImageMemory ( mVulkanRenderer.GetDevice(), mVkDepthStencilImage, mVkDepthStencilImageMemory, 0 ); VkImageViewCreateInfo image_view_create_info{}; image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; image_view_create_info.image = mVkDepthStencilImage; image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; image_view_create_info.format = mVulkanRenderer.GetDepthStencilFormat(); image_view_create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; image_view_create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; image_view_create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; image_view_create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | ( mHasStencil ? VK_IMAGE_ASPECT_STENCIL_BIT : 0 ); image_view_create_info.subresourceRange.baseMipLevel = 0; image_view_create_info.subresourceRange.levelCount = 1; image_view_create_info.subresourceRange.baseArrayLayer = 0; image_view_create_info.subresourceRange.layerCount = 1; vkCreateImageView ( mVulkanRenderer.GetDevice(), &image_view_create_info, nullptr, &mVkDepthStencilImageView ); }
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 ); } }