From ce8bc3a96b5016983469819345e7fa51d5bbd693 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Apr 2025 18:01:31 +0200 Subject: [PATCH] Implemented Maximal MSAA --- vulkan/vulkan_app.cpp | 67 ++++++++++++++++++++++++++++++++++++------- vulkan/vulkan_app.hpp | 10 ++++++- 2 files changed, 66 insertions(+), 11 deletions(-) diff --git a/vulkan/vulkan_app.cpp b/vulkan/vulkan_app.cpp index 6319962..4aa9906 100644 --- a/vulkan/vulkan_app.cpp +++ b/vulkan/vulkan_app.cpp @@ -101,6 +101,23 @@ namespace vapp{ return extensions; } + VkSampleCountFlagBits Vulkan::getMaxUsableSampleCount() + { + VkPhysicalDeviceProperties physicalDeviceProperties; + vkGetPhysicalDeviceProperties(physicalDevice, &physicalDeviceProperties); + + VkSampleCountFlags counts = physicalDeviceProperties.limits.framebufferDepthSampleCounts; + + if (counts & VK_SAMPLE_COUNT_64_BIT) return VK_SAMPLE_COUNT_64_BIT; + if (counts & VK_SAMPLE_COUNT_32_BIT) return VK_SAMPLE_COUNT_32_BIT; + if (counts & VK_SAMPLE_COUNT_16_BIT) return VK_SAMPLE_COUNT_16_BIT; + if (counts & VK_SAMPLE_COUNT_8_BIT) return VK_SAMPLE_COUNT_8_BIT; + if (counts & VK_SAMPLE_COUNT_4_BIT) return VK_SAMPLE_COUNT_4_BIT; + if (counts & VK_SAMPLE_COUNT_2_BIT) return VK_SAMPLE_COUNT_2_BIT; + + return VK_SAMPLE_COUNT_1_BIT; + } + void Vulkan::createInstance(){ if(enableValidationLayers && !checkValidationLayerSupport()){ throw std::runtime_error("Func: createInstance\nError: Validation Layers requested, but not available!\n"); @@ -174,6 +191,7 @@ namespace vapp{ for(VkPhysicalDevice device : devices){ if(isDeviceSuitable(device)){ physicalDevice = device; + msaaSamples = getMaxUsableSampleCount(); break; } } @@ -535,7 +553,7 @@ namespace vapp{ VkPipelineMultisampleStateCreateInfo multisampling{}; multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; multisampling.sampleShadingEnable = VK_FALSE; - multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + multisampling.rasterizationSamples = msaaSamples; VkPipelineColorBlendAttachmentState colorBlendAttachment{}; colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT @@ -626,7 +644,7 @@ namespace vapp{ void Vulkan::createRenderPass(){ VkAttachmentDescription depthAttachment{}; depthAttachment.format = findDepthFormat(); - depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT; + depthAttachment.samples = msaaSamples; depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; @@ -640,23 +658,38 @@ namespace vapp{ VkAttachmentDescription colorAttachment{}; colorAttachment.format = swapChainImageFormat; - colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; + colorAttachment.samples = msaaSamples; colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + colorAttachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; VkAttachmentReference colorAttachmentRef{}; colorAttachmentRef.attachment = 0; colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + VkAttachmentDescription colorAttachmentResolve{}; + colorAttachmentResolve.format = swapChainImageFormat; + colorAttachmentResolve.samples = VK_SAMPLE_COUNT_1_BIT; + colorAttachmentResolve.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + colorAttachmentResolve.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + colorAttachmentResolve.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + colorAttachmentResolve.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + colorAttachmentResolve.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + colorAttachmentResolve.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + + VkAttachmentReference colorAttachmentResolveRef{}; + colorAttachmentResolveRef.attachment = 2; + colorAttachmentResolveRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + VkSubpassDescription subpass{}; subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; subpass.colorAttachmentCount = 1; subpass.pColorAttachments = &colorAttachmentRef; subpass.pDepthStencilAttachment = &depthAttachmentRef; + subpass.pResolveAttachments = &colorAttachmentResolveRef; VkSubpassDependency dependency{}; dependency.srcSubpass = VK_SUBPASS_EXTERNAL; @@ -666,7 +699,7 @@ namespace vapp{ dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;; dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;; - std::array attachments = { colorAttachment, depthAttachment }; + std::array attachments = { colorAttachment, depthAttachment, colorAttachmentResolve }; VkRenderPassCreateInfo renderPassInfo{}; renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; @@ -686,7 +719,7 @@ namespace vapp{ swapChainFramebuffers.resize(swapChainImageViews.size()); for(size_t i = 0; i < swapChainImageViews.size(); i++){ - std::array attachments = { swapChainImageViews[i], depthImageView }; + std::array attachments = { colorImageView, depthImageView, swapChainImageViews[i] }; VkFramebufferCreateInfo framebufferInfo{}; framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; @@ -743,9 +776,17 @@ namespace vapp{ return format == VK_FORMAT_D32_SFLOAT_S8_UINT || format == VK_FORMAT_D24_UNORM_S8_UINT; } + void Vulkan::createColorResources() + { + VkFormat colorFormat = swapChainImageFormat; + + createImage(swapChainExtent.width, swapChainExtent.height, 1, msaaSamples, colorFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, colorImage, colorImageMemory); + colorImageView = createImageView(colorImage, colorFormat, VK_IMAGE_ASPECT_COLOR_BIT, 1); + } + void Vulkan::createDepthResources(){ VkFormat depthFormat = findDepthFormat(); - createImage(swapChainExtent.width, swapChainExtent.height, 1, depthFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, depthImage, depthImageMemory); + createImage(swapChainExtent.width, swapChainExtent.height, 1, msaaSamples, depthFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, depthImage, depthImageMemory); depthImageView = createImageView(depthImage, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT, 1); } @@ -855,7 +896,7 @@ namespace vapp{ endSingleTimeCommands(commandBuffer); } - void Vulkan::createImage(uint32_t width, uint32_t height, uint32_t mipLevels, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage &image, VkDeviceMemory &imageMemory){ + void Vulkan::createImage(uint32_t width, uint32_t height, uint32_t mipLevels, VkSampleCountFlagBits numSamples, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage &image, VkDeviceMemory &imageMemory){ VkImageCreateInfo imageInfo{}; imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; imageInfo.imageType = VK_IMAGE_TYPE_2D; // 3D is used to store voxel volumes @@ -869,7 +910,7 @@ namespace vapp{ imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; imageInfo.usage = usage; imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; + imageInfo.samples = numSamples; imageInfo.flags = 0; // something tells me this has another value when using voxels if(vkCreateImage(device, &imageInfo, nullptr, &image) != VK_SUCCESS){ @@ -991,7 +1032,7 @@ namespace vapp{ stbi_image_free(pixels); - createImage(texWidth, texHeight, mipLevels, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, textureImage, textureImageMemory); + createImage(texWidth, texHeight, mipLevels, VK_SAMPLE_COUNT_1_BIT, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, textureImage, textureImageMemory); transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, mipLevels); copyBufferToImage(stagingBuffer, textureImage, static_cast(texWidth), static_cast(texHeight)); // removed because of mipmapping @@ -1463,6 +1504,10 @@ namespace vapp{ } void Vulkan::cleanupSwapChain(){ + vkDestroyImageView(device, colorImageView, nullptr); + vkDestroyImage(device, colorImage, nullptr); + vkFreeMemory(device, colorImageMemory, nullptr); + vkDestroyImageView(device, depthImageView, nullptr); vkDestroyImage(device, depthImage, nullptr); vkFreeMemory(device, depthImageMemory, nullptr); @@ -1488,6 +1533,7 @@ namespace vapp{ createSwapChain(); createImageViews(); + createColorResources(); createDepthResources(); createFramebuffers(); } @@ -1518,6 +1564,7 @@ namespace vapp{ createDescriptorSetLayout(); createGraphicsPipeline(); createCommandPool(); + createColorResources(); createDepthResources(); createFramebuffers(); createTextureImage(); diff --git a/vulkan/vulkan_app.hpp b/vulkan/vulkan_app.hpp index f3e9733..e6b5e27 100644 --- a/vulkan/vulkan_app.hpp +++ b/vulkan/vulkan_app.hpp @@ -183,10 +183,15 @@ namespace vapp{ VkImage depthImage; VkDeviceMemory depthImageMemory; VkImageView depthImageView; + + VkImage colorImage; + VkDeviceMemory colorImageMemory; + VkImageView colorImageView; #pragma endregion #pragma region PrivateFunctions bool checkValidationLayerSupport(); std::vector getRequiredExtensions(); + VkSampleCountFlagBits getMaxUsableSampleCount(); void createInstance(); void setupDebugMessenger(); @@ -210,12 +215,13 @@ namespace vapp{ void createCommandPool(); VkFormat findSupportedFormat(const std::vector &candidates, VkImageTiling tiling, VkFormatFeatureFlags features); VkFormat findDepthFormat(); + void createColorResources(); void createDepthResources(); VkCommandBuffer beginSingleTimeCommands(); void endSingleTimeCommands(VkCommandBuffer commandBuffer); void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t mipLevels); void copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height); - void createImage(uint32_t width, uint32_t height, uint32_t mipLevels, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory &imageMemory); + void createImage(uint32_t width, uint32_t height, uint32_t mipLevels, VkSampleCountFlagBits numSamples, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory &imageMemory); void generateMipmaps(VkImage image, VkFormat imageFormat, int32_t texWidth, int32_t texHeight, uint32_t mipLevels); void createTextureImage(); VkImageView createImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags, uint32_t mipLevels); @@ -254,6 +260,8 @@ namespace vapp{ bool framebufferResized = false; std::string MODEL_PATH; std::string TEXTURE_PATH; + + VkSampleCountFlagBits msaaSamples = VK_SAMPLE_COUNT_1_BIT; #pragma endregion #pragma region PublicFunctions void run(const char *windowName, const uint32_t width = 800, const uint32_t height = 600);