From 9f608cda6028a87225da0051cb9219f5b205cd1e Mon Sep 17 00:00:00 2001 From: InkSoul Date: Thu, 29 Feb 2024 23:05:44 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90swapChain=E5=88=9B=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- VulkanTutorial.cpp | 185 +++++++++++++++++++++++++++++++++++++++++++-- VulkanTutorial.h | 26 ++++++- 2 files changed, 205 insertions(+), 6 deletions(-) diff --git a/VulkanTutorial.cpp b/VulkanTutorial.cpp index 74d7c95..39a7f06 100644 --- a/VulkanTutorial.cpp +++ b/VulkanTutorial.cpp @@ -11,6 +11,10 @@ const std::vector validationLayers = { }; +const std::vector swapchainExtensions = { + VK_KHR_SWAPCHAIN_EXTENSION_NAME +}; + #ifdef NDEBUG const bool enableValidationLayers = false; #else @@ -103,6 +107,8 @@ void HelloTriangleApplication::initVulkan() { pickPhysicalDevice(); createLogicalDevice(); + + createSwapChain(); } @@ -120,14 +126,16 @@ void HelloTriangleApplication::mainLoop(GLFWwindow* window){ void HelloTriangleApplication::cleanup(GLFWwindow* window) { - vkDestroyDevice(device, nullptr); + vkDestroySwapchainKHR(device, swapChain, nullptr); + + vkDestroySurfaceKHR(instance, surface, nullptr); if (enableValidationLayers) { DestroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr); } - vkDestroySurfaceKHR(instance, surface, nullptr); + vkDestroyDevice(device, nullptr); vkDestroyInstance(instance, nullptr); @@ -222,6 +230,25 @@ void HelloTriangleApplication::createSurface() } } +bool HelloTriangleApplication::checkDeviceExtensionSupport(VkPhysicalDevice device) +{ + uint32_t extensionCount; + vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr); + + std::vector availableExtensions(extensionCount); + vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data()); + + std::set requiredExtensions(swapchainExtensions.begin(), swapchainExtensions.end()); + + for (const auto& extension : availableExtensions) + { + requiredExtensions.erase(extension.extensionName); + } + + return requiredExtensions.empty(); + +} + void HelloTriangleApplication::pickPhysicalDevice() { uint32_t deviceCount = 0; @@ -255,7 +282,16 @@ bool HelloTriangleApplication::isDeviceSuitable(VkPhysicalDevice device) { QueueFamilyIndices indices = findQueueFamilies(device); - return indices.isComplete(); + bool extensionsSupported = checkDeviceExtensionSupport(device); + + bool swapChainAdequate = false; + if (extensionsSupported) + { + SwapChainSupportDetails swapChainSupport = querySwapChainSupport(device); + swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty(); + } + + return indices.isComplete() && extensionsSupported && swapChainAdequate; } HelloTriangleApplication::QueueFamilyIndices HelloTriangleApplication::findQueueFamilies(VkPhysicalDevice device) @@ -321,14 +357,16 @@ void HelloTriangleApplication::createLogicalDevice() float queuePriority = 1.0f; queueCreateInfo.pQueuePriorities = &queuePriority; */ - + VkPhysicalDeviceFeatures deviceFeatures{}; VkDeviceCreateInfo deviceCreateInfo{}; deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; deviceCreateInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); deviceCreateInfo.pQueueCreateInfos = queueCreateInfos.data(); deviceCreateInfo.pEnabledFeatures = &deviceFeatures; + deviceCreateInfo.enabledExtensionCount = static_cast(swapchainExtensions.size()); + deviceCreateInfo.ppEnabledExtensionNames = swapchainExtensions.data(); //新版本vulkan已不对实例和设备特定验证层做区分,此处保证兼容性 - deviceCreateInfo.enabledExtensionCount = 0; + if (enableValidationLayers) { deviceCreateInfo.enabledLayerCount = static_cast(validationLayers.size()); @@ -348,6 +386,143 @@ void HelloTriangleApplication::createLogicalDevice() vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue); } +HelloTriangleApplication::SwapChainSupportDetails HelloTriangleApplication::querySwapChainSupport(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; +} + +VkSurfaceFormatKHR HelloTriangleApplication::chooseSwapSurfaceFormat(const std::vector& availableFormats) +{ + for (const auto& availableFormat : availableFormats) { + if (availableFormat.format == VK_FORMAT_B8G8R8_SRGB && availableFormat.colorSpace == VK_COLORSPACE_SRGB_NONLINEAR_KHR) + { + return availableFormat; + } + } + + return availableFormats[0]; +} + +VkPresentModeKHR HelloTriangleApplication::chooseSwapPresentMode(const std::vector& availablePresentModes) +{ + for (const auto& availablePresentMode : availablePresentModes) { + if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) + { + return availablePresentMode; + } + } + + return VK_PRESENT_MODE_FIFO_KHR; +} + +VkExtent2D HelloTriangleApplication::chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities) +{ + if (capabilities.currentExtent.width != std::numeric_limits::max()) + { + return capabilities.currentExtent; + } + else + { + int width, height; + glfwGetFramebufferSize(window, &width, &height); + + VkExtent2D actualExtent = { + static_cast(width), + static_cast(height) + }; + + actualExtent.width = std::clamp(actualExtent.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width); + actualExtent.height = std::clamp(actualExtent.height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height); + + return actualExtent; + } +} + +void HelloTriangleApplication::createSwapChain() +{ + SwapChainSupportDetails swapChainSupport = querySwapChainSupport(physicalDevice); + + VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats); + VkPresentModeKHR presentMode = chooseSwapPresentMode(swapChainSupport.presentModes); + VkExtent2D extent = chooseSwapExtent(swapChainSupport.capabilities); + + uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1; + + if (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount) + { + imageCount = swapChainSupport.capabilities.maxImageCount; + } + + VkSwapchainCreateInfoKHR createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + createInfo.surface = surface; + + createInfo.minImageCount = imageCount; + createInfo.imageFormat = surfaceFormat.format; + createInfo.imageColorSpace = surfaceFormat.colorSpace; + createInfo.imageExtent = extent; + createInfo.imageArrayLayers = 1; + createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + + QueueFamilyIndices indices = findQueueFamilies(physicalDevice); + uint32_t queueFamilyIndices[] = { indices.graphicsFamily.value(),indices.presentFamily.value() }; + if (indices.graphicsFamily != indices.presentFamily) + { + createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; + createInfo.queueFamilyIndexCount = 2; + createInfo.pQueueFamilyIndices = queueFamilyIndices; + + } + else + { + createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + createInfo.queueFamilyIndexCount = 0; + createInfo.pQueueFamilyIndices = nullptr; + } + + createInfo.preTransform = swapChainSupport.capabilities.currentTransform; + createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + createInfo.presentMode = presentMode; + createInfo.clipped = VK_TRUE; + createInfo.oldSwapchain = VK_NULL_HANDLE; + + + if (vkCreateSwapchainKHR(device,&createInfo,nullptr,&swapChain) != VK_SUCCESS) + { + throw std::runtime_error("failed to create swap chain !"); + } + + vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr); + swapChainImages.resize(imageCount); + vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data()); + // store swap format and swap extent to member variable + swapChainImageFormat = surfaceFormat.format; + swapChainExtent = extent; + +} + bool HelloTriangleApplication::checkValidationLayerSupport() { uint32_t layerCount; diff --git a/VulkanTutorial.h b/VulkanTutorial.h index 2415eb9..6f8dc83 100644 --- a/VulkanTutorial.h +++ b/VulkanTutorial.h @@ -15,6 +15,11 @@ #include #include +#include +#include +#include + + VkResult CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,const VkAllocationCallbacks* pAllocator,VkDebugUtilsMessengerEXT* pDebugMessenger); void DestroyDebugUtilsMessengerEXT(VkInstance instance,VkDebugUtilsMessengerEXT debugMessenger,const VkAllocationCallbacks* pAllocator); @@ -43,13 +48,17 @@ private: VkDevice device; - VkPhysicalDeviceFeatures deviceFeatures{}; VkQueue graphicQueue; VkQueue presentQueue; VkSurfaceKHR surface; + VkSwapchainKHR swapChain; + std::vector swapChainImages; + VkFormat swapChainImageFormat; + VkExtent2D swapChainExtent; + struct QueueFamilyIndices { std::optional graphicsFamily; @@ -60,6 +69,12 @@ private: } }; + struct SwapChainSupportDetails + { + VkSurfaceCapabilitiesKHR capabilities; + std::vector formats; + std::vector presentModes; + }; GLFWwindow* initWindow(int Width, int Height); @@ -89,6 +104,8 @@ private: void createSurface(); + bool checkDeviceExtensionSupport(VkPhysicalDevice device); + void pickPhysicalDevice(); bool isDeviceSuitable(VkPhysicalDevice device); @@ -96,6 +113,13 @@ private: void createLogicalDevice(); + SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device); + + VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector& availableFormats); + VkPresentModeKHR chooseSwapPresentMode(const std::vector& availablePresentModes); + VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities); + void createSwapChain(); + }; HelloTriangleApplication::HelloTriangleApplication()