diff --git a/vulkan/Application.cpp b/vulkan/Application.cpp index c80b0f6..9834738 100644 --- a/vulkan/Application.cpp +++ b/vulkan/Application.cpp @@ -70,7 +70,9 @@ void Application::initVulkan() pickPhysicalDevice(physicalDevice, surface); // 选择物理设备 createLogicalDevice(); // 创建逻辑设备 createSwapChain(); // 创建交换链 + createImages(); createImageViews(); // 创建交换链图像视图 + createColorResources(); createRenderPass(); // 创建渲染流程 createPipelineLayout(); // 在这里调用 createGraphicsPipeline(); // 创建图形管线 @@ -81,6 +83,14 @@ void Application::initVulkan() inited = true; } +void Application::createImages() +{ + uint32_t imageCount = 0; + vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr); + swapChainImages.resize(imageCount); + vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data()); +} + void Application::createImageViews() { swapChainImageViews.resize(swapChainImages.size()); @@ -105,20 +115,23 @@ void Application::createImageViews() { } } } - -void Application::createFramebuffers() { +void Application::createFramebuffers() +{ swapChainFramebuffers.resize(swapChainImageViews.size()); - for (size_t i = 0; i < swapChainImageViews.size(); i++) { - VkImageView attachments[] = { - swapChainImageViews[i] + for (size_t i = 0; i < swapChainImageViews.size(); i++) + { + std::vector attachments = + { + colorImageView, // 0: MSAA color attachment + swapChainImageViews[i] // 1: resolve target (swapchain) }; VkFramebufferCreateInfo framebufferInfo{}; framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; framebufferInfo.renderPass = renderPass; - framebufferInfo.attachmentCount = 1; - framebufferInfo.pAttachments = attachments; + framebufferInfo.attachmentCount = static_cast(attachments.size()); + framebufferInfo.pAttachments = attachments.data(); framebufferInfo.width = swapChainExtent.width; framebufferInfo.height = swapChainExtent.height; framebufferInfo.layers = 1; @@ -232,15 +245,12 @@ void Application::createSwapChain() { throw std::runtime_error("failed to create swap chain!"); } - - vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr); - swapChainImages.resize(imageCount); - vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data()); - swapChainImageFormat = surfaceFormat.format; swapChainExtent = extent; } + + void Application::createPipelineLayout() { VkPipelineLayoutCreateInfo pipelineLayoutInfo{}; pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; @@ -327,7 +337,7 @@ void Application::createGraphicsPipeline() { 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 = VK_SAMPLE_COUNT_8_BIT; // 颜色混合状态 VkPipelineColorBlendAttachmentState colorBlendAttachment{}; @@ -365,31 +375,62 @@ void Application::createGraphicsPipeline() { } void Application::createRenderPass() { + // 1. 多重采样颜色附件(8x) VkAttachmentDescription colorAttachment{}; colorAttachment.format = swapChainImageFormat; - colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; + colorAttachment.samples = VK_SAMPLE_COUNT_8_BIT; // ←←← 8x colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; // 不需要存储,因为会 resolve 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; + // 2. Resolve 附件(普通 swapchain image) + VkAttachmentDescription resolveAttachment{}; + resolveAttachment.format = swapChainImageFormat; + resolveAttachment.samples = VK_SAMPLE_COUNT_1_BIT; // ←←← resolve 到单采样 + resolveAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + resolveAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + resolveAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + resolveAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + resolveAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + resolveAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + + // 引用 VkAttachmentReference colorAttachmentRef{}; colorAttachmentRef.attachment = 0; colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + VkAttachmentReference resolveAttachmentRef{}; + resolveAttachmentRef.attachment = 1; + resolveAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + // Subpass:指定 color 和 resolve VkSubpassDescription subpass{}; subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; subpass.colorAttachmentCount = 1; subpass.pColorAttachments = &colorAttachmentRef; + subpass.pResolveAttachments = &resolveAttachmentRef; // ←←← 关键! + // Subpass 依赖(可选但推荐) + VkSubpassDependency dependency{}; + dependency.srcSubpass = VK_SUBPASS_EXTERNAL; + dependency.dstSubpass = 0; + dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependency.srcAccessMask = 0; + dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + + std::vector attachments = { colorAttachment, resolveAttachment }; VkRenderPassCreateInfo renderPassInfo{}; renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - renderPassInfo.attachmentCount = 1; - renderPassInfo.pAttachments = &colorAttachment; + renderPassInfo.attachmentCount = static_cast(attachments.size()); + renderPassInfo.pAttachments = attachments.data(); renderPassInfo.subpassCount = 1; renderPassInfo.pSubpasses = &subpass; + renderPassInfo.dependencyCount = 1; + renderPassInfo.pDependencies = &dependency; if (vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass) != VK_SUCCESS) { throw std::runtime_error("failed to create render pass!"); @@ -397,7 +438,6 @@ void Application::createRenderPass() { } - void Application::createCommandPool() { QueueFamilyIndices queueFamilyIndices = findQueueFamilies(physicalDevice, surface); @@ -488,17 +528,18 @@ void Application::recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t im void Application::drawLeft() { - cout << "call drawLeft curFrame:" << to_string(currentFrame) << endl; + if(showDrawDebug) + cout << "call drawLeft curFrame:" << to_string(currentFrame) << endl; // 1. 等待前一帧完成 vkWaitForFences(device, 1, &inFlightFences_Left, VK_TRUE, UINT64_MAX); - cout << "vkWaitForFences inFlightFences_Left" << endl; + if (showDrawDebug) cout << "vkWaitForFences inFlightFences_Left" << endl; // 2. 获取交换链图像 - 使用当前帧的信号量 uint32_t imageIndex; VkResult result = vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, imageAvailableSemaphores_Left, VK_NULL_HANDLE, &imageIndex); - cout << "vkAcquireNextImageKHR set imageAvailableSemaphores_Left ImageIndex:" << to_string(imageIndex) << endl; + if (showDrawDebug) cout << "vkAcquireNextImageKHR set imageAvailableSemaphores_Left ImageIndex:" << to_string(imageIndex) << endl; if (result != VK_SUCCESS) { throw std::runtime_error("failed to acquire swap chain image!"); @@ -508,15 +549,15 @@ void Application::drawLeft() { // 3. 检查该图像是否正在被之前的帧使用 if (imagesInFlight_Left != VK_NULL_HANDLE) { - cout << "vkWaitForFences imagesInFlight_Left ImageIndex:" << to_string(imageIndex) << endl; + if (showDrawDebug) cout << "vkWaitForFences imagesInFlight_Left ImageIndex:" << to_string(imageIndex) << endl; vkWaitForFences(device, 1, &imagesInFlight_Left, VK_TRUE, UINT64_MAX); } else { - cout << "imagesInFlight_Left is NULL" << endl; + if (showDrawDebug) cout << "imagesInFlight_Left is NULL" << endl; } - cout << "imagesInFlight_Left = inFlightFences_Left ImageIndex:" << to_string(imageIndex) << endl; + if (showDrawDebug) cout << "imagesInFlight_Left = inFlightFences_Left ImageIndex:" << to_string(imageIndex) << endl; // 标记该图像正在被当前帧使用 imagesInFlight_Left = inFlightFences_Left; } @@ -524,18 +565,18 @@ void Application::drawLeft() { // 3. 检查该图像是否正在被之前的帧使用 if (imagesInFlight_Right != VK_NULL_HANDLE) { - cout << "vkWaitForFences imagesInFlight_Right ImageIndex:" << to_string(imageIndex) << endl; + if (showDrawDebug) cout << "vkWaitForFences imagesInFlight_Right ImageIndex:" << to_string(imageIndex) << endl; vkWaitForFences(device, 1, &imagesInFlight_Right, VK_TRUE, UINT64_MAX); } - cout << "imagesInFlight_Right = inFlightFences_Left ImageIndex:" << to_string(imageIndex) << endl; + if (showDrawDebug) cout << "imagesInFlight_Right = inFlightFences_Left ImageIndex:" << to_string(imageIndex) << endl; imagesInFlight_Right = inFlightFences_Left; } - cout << "vkResetFences inFlightFences_Left" << endl; + if (showDrawDebug) cout << "vkResetFences inFlightFences_Left" << endl; // 4. 重置栅栏 vkResetFences(device, 1, &inFlightFences_Left); - cout << "Process commandBuffers_Left" << endl; + if (showDrawDebug) cout << "Process commandBuffers_Left" << endl; // 5. 记录命令缓冲区 vkResetCommandBuffer(commandBuffers_Left, 0); recordCommandBuffer(commandBuffers_Left, imageIndex); @@ -556,21 +597,21 @@ void Application::drawLeft() VkSemaphore signalSemaphores[1]; if (imageIndex == 0) { - cout << "renderFinishedSemaphores_Left ImageIndex:" << to_string(imageIndex) << endl; + if (showDrawDebug) cout << "renderFinishedSemaphores_Left ImageIndex:" << to_string(imageIndex) << endl; // 使用对应图像的渲染完成信号量 signalSemaphores[0] = { renderFinishedSemaphores_Left }; } else { - cout << "renderFinishedSemaphores_Right ImageIndex:" << to_string(imageIndex) << endl; + if (showDrawDebug) cout << "renderFinishedSemaphores_Right ImageIndex:" << to_string(imageIndex) << endl; // 使用对应图像的渲染完成信号量 signalSemaphores[0] = { renderFinishedSemaphores_Right }; } submitInfo.signalSemaphoreCount = 1; submitInfo.pSignalSemaphores = signalSemaphores; - cout << "vkQueueSubmit inFlightFences_Left" << endl; + if (showDrawDebug) cout << "vkQueueSubmit inFlightFences_Left" << endl; if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFences_Left) != VK_SUCCESS) { throw std::runtime_error("failed to submit draw command buffer!"); } @@ -586,7 +627,7 @@ void Application::drawLeft() presentInfo.pSwapchains = swapChains; presentInfo.pImageIndices = &imageIndex; - cout << "Present Left \n" << endl; + if (showDrawDebug) cout << "Present Left \n" << endl; result = vkQueuePresentKHR(presentQueue, &presentInfo); if (result != VK_SUCCESS) { @@ -597,17 +638,17 @@ void Application::drawLeft() void Application::drawRight() { - cout << "call drawRight curFrame:" << to_string(currentFrame) << endl; + if (showDrawDebug) cout << "call drawRight curFrame:" << to_string(currentFrame) << endl; // 1. 等待前一帧完成 vkWaitForFences(device, 1, &inFlightFences_Right, VK_TRUE, UINT64_MAX); - cout << "vkWaitForFences inFlightFences_Right" << endl; + if (showDrawDebug) cout << "vkWaitForFences inFlightFences_Right" << endl; // 2. 获取交换链图像 - 使用当前帧的信号量 uint32_t imageIndex; VkResult result = vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, imageAvailableSemaphores_Right, VK_NULL_HANDLE, &imageIndex); - cout << "vkAcquireNextImageKHR set imageAvailableSemaphores_Right ImageIndex:" << to_string(imageIndex) << endl; + if (showDrawDebug) cout << "vkAcquireNextImageKHR set imageAvailableSemaphores_Right ImageIndex:" << to_string(imageIndex) << endl; if (result != VK_SUCCESS) { throw std::runtime_error("failed to acquire swap chain image!"); @@ -617,10 +658,10 @@ void Application::drawRight() { // 3. 检查该图像是否正在被之前的帧使用 if (imagesInFlight_Left != VK_NULL_HANDLE) { - cout << "vkWaitForFences imagesInFlight_Left ImageIndex:0" << endl; + if (showDrawDebug) cout << "vkWaitForFences imagesInFlight_Left ImageIndex:0" << endl; vkWaitForFences(device, 1, &imagesInFlight_Left, VK_TRUE, UINT64_MAX); } - cout << "imagesInFlight_Left = inFlightFences_Right ImageIndex:0" << endl; + if (showDrawDebug) cout << "imagesInFlight_Left = inFlightFences_Right ImageIndex:0" << endl; // 标记该图像正在被当前帧使用 imagesInFlight_Left = inFlightFences_Right; } @@ -628,21 +669,21 @@ void Application::drawRight() { // 3. 检查该图像是否正在被之前的帧使用 if (imagesInFlight_Right != VK_NULL_HANDLE) { - cout << "vkWaitForFences imagesInFlight_Right ImageIndex:1" << endl; + if (showDrawDebug) cout << "vkWaitForFences imagesInFlight_Right ImageIndex:1" << endl; vkWaitForFences(device, 1, &imagesInFlight_Right, VK_TRUE, UINT64_MAX); } else { - cout << "imagesInFlight_Right is NULL" << endl; + if (showDrawDebug) cout << "imagesInFlight_Right is NULL" << endl; } - cout << "imagesInFlight_Right = inFlightFences_Right ImageIndex:1" << endl; + if (showDrawDebug) cout << "imagesInFlight_Right = inFlightFences_Right ImageIndex:1" << endl; imagesInFlight_Right = inFlightFences_Right; } - cout << "vkResetFences inFlightFences_Right" << endl; + if (showDrawDebug) cout << "vkResetFences inFlightFences_Right" << endl; // 4. 重置栅栏 vkResetFences(device, 1, &inFlightFences_Right); - cout << "Process commandBuffers_Right" << endl; + if (showDrawDebug) cout << "Process commandBuffers_Right" << endl; // 5. 记录命令缓冲区 vkResetCommandBuffer(commandBuffers_Right, 0); recordCommandBuffer(commandBuffers_Right, imageIndex); @@ -663,21 +704,21 @@ void Application::drawRight() VkSemaphore signalSemaphores[1]; if (imageIndex == 0) { - cout << "renderFinishedSemaphores_Left ImageIndex:0" << endl; + if (showDrawDebug) cout << "renderFinishedSemaphores_Left ImageIndex:0" << endl; // 使用对应图像的渲染完成信号量 signalSemaphores[0] = { renderFinishedSemaphores_Left }; } else { - cout << "renderFinishedSemaphores_Right ImageIndex:1" << endl; + if (showDrawDebug) cout << "renderFinishedSemaphores_Right ImageIndex:1" << endl; // 使用对应图像的渲染完成信号量 signalSemaphores[0] = { renderFinishedSemaphores_Right }; } submitInfo.signalSemaphoreCount = 1; submitInfo.pSignalSemaphores = signalSemaphores; - cout << "vkQueueSubmit inFlightFences_Right" << endl; + if (showDrawDebug) cout << "vkQueueSubmit inFlightFences_Right" << endl; if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFences_Right) != VK_SUCCESS) { throw std::runtime_error("failed to submit draw command buffer!"); } @@ -693,7 +734,7 @@ void Application::drawRight() presentInfo.pSwapchains = swapChains; presentInfo.pImageIndices = &imageIndex; - cout << "Present Right \n" << endl; + if (showDrawDebug) cout << "Present Right \n" << endl; result = vkQueuePresentKHR(presentQueue, &presentInfo); if (result != VK_SUCCESS) { @@ -721,6 +762,77 @@ void DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT } } +void Application::createColorResources() { + VkFormat colorFormat = swapChainImageFormat; + + VkImageCreateInfo imageInfo{}; + imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageInfo.imageType = VK_IMAGE_TYPE_2D; + imageInfo.format = colorFormat; + imageInfo.extent.width = swapChainExtent.width; + imageInfo.extent.height = swapChainExtent.height; + imageInfo.extent.depth = 1; + imageInfo.mipLevels = 1; + imageInfo.arrayLayers = 1; + imageInfo.samples = VK_SAMPLE_COUNT_8_BIT; // ←←← 8x MSAA + imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imageInfo.usage = VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + if (vkCreateImage(device, &imageInfo, nullptr, &colorImage) != VK_SUCCESS) { + throw std::runtime_error("failed to create MSAA color image!"); + } + + VkMemoryRequirements memRequirements; + vkGetImageMemoryRequirements(device, colorImage, &memRequirements); + + VkMemoryAllocateInfo allocInfo{}; + allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocInfo.allocationSize = memRequirements.size; + allocInfo.memoryTypeIndex = findMemoryType(physicalDevice, memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + + if (vkAllocateMemory(device, &allocInfo, nullptr, &colorImageMemory) != VK_SUCCESS) { + throw std::runtime_error("failed to allocate MSAA color image memory!"); + } + + vkBindImageMemory(device, colorImage, colorImageMemory, 0); + + // 创建 ImageView + VkImageViewCreateInfo viewInfo{}; + viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + viewInfo.image = colorImage; + viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.format = colorFormat; + viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + viewInfo.subresourceRange.baseMipLevel = 0; + viewInfo.subresourceRange.levelCount = 1; + viewInfo.subresourceRange.baseArrayLayer = 0; + viewInfo.subresourceRange.layerCount = 1; + + if (vkCreateImageView(device, &viewInfo, nullptr, &colorImageView) != VK_SUCCESS) { + throw std::runtime_error("failed to create MSAA color image view!"); + } +} + + +uint32_t Application::findMemoryType(VkPhysicalDevice physicalDevice, uint32_t typeFilter, + VkMemoryPropertyFlags properties) +{ + VkPhysicalDeviceMemoryProperties memProperties; + vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties); + + for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) + { + if ((typeFilter & (1 << i)) && + (memProperties.memoryTypes[i].propertyFlags & properties) == properties) + { + return i; + } + } + + throw std::runtime_error("Failed to find suitable memory type!"); +} + void Application::cleanup() { if (enableValidationLayers) { DestroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr); @@ -758,6 +870,10 @@ void Application::cleanup() { vkDestroyImageView(device, imageView, nullptr); } + vkDestroyImageView(device, colorImageView, nullptr); + vkDestroyImage(device, colorImage, nullptr); + vkFreeMemory(device, colorImageMemory, nullptr); + // 销毁交换链 vkDestroySwapchainKHR(device, swapChain, nullptr); @@ -773,6 +889,7 @@ void Application::cleanup() { // 销毁 Vulkan 实例 vkDestroyInstance(instance, nullptr); + #ifdef _WIN32 // 销毁 GLFW 窗口 glfwDestroyWindow(window); diff --git a/vulkan/Application.h b/vulkan/Application.h index 26fd3e9..e90a04c 100644 --- a/vulkan/Application.h +++ b/vulkan/Application.h @@ -17,6 +17,7 @@ public: void mainLoop(); void cleanup(); + void createImages(); void createImageViews(); void createFramebuffers(); void createCommandPool(); @@ -65,6 +66,17 @@ private: VkFence imagesInFlight_Left = VK_NULL_HANDLE; VkFence imagesInFlight_Right = VK_NULL_HANDLE; + const bool showDrawDebug = false; + int currentFrame = 0; bool inited = false; + + //MSAA + VkImage colorImage; + VkDeviceMemory colorImageMemory; + VkImageView colorImageView; + void createColorResources(); + uint32_t findMemoryType(VkPhysicalDevice physicalDevice, uint32_t typeFilter, + VkMemoryPropertyFlags properties); + }; \ No newline at end of file