diff --git a/src/vulkanrenderer.cpp b/src/vulkanrenderer.cpp index 27d83c3..549b88a 100644 --- a/src/vulkanrenderer.cpp +++ b/src/vulkanrenderer.cpp @@ -53,6 +53,10 @@ VulkanRenderer::VulkanRenderer() , m_fontTextureMemory(VK_NULL_HANDLE) , m_fontTextureView(VK_NULL_HANDLE) , m_fontSampler(VK_NULL_HANDLE) + , m_msaaImage(VK_NULL_HANDLE) + , m_msaaImageMemory(VK_NULL_HANDLE) + , m_msaaImageView(VK_NULL_HANDLE) + , m_msaaSamples(VK_SAMPLE_COUNT_1_BIT) , m_width(0) , m_height(0) , m_swapchainFormat(0) @@ -80,6 +84,18 @@ bool VulkanRenderer::initialize(VkDevice device, VkPhysicalDevice physicalDevice m_height = height; m_transferCommandPool = VK_NULL_HANDLE; + // Determine best MSAA sample count + m_msaaSamples = getMaxUsableSampleCount(); + std::cout << "Using MSAA with " << m_msaaSamples << " samples" << std::endl; + + // Create MSAA resources if MSAA is enabled + if (m_msaaSamples > VK_SAMPLE_COUNT_1_BIT) { + if (!createMSAAResources()) { + logError("Failed to create MSAA resources, falling back to no MSAA"); + m_msaaSamples = VK_SAMPLE_COUNT_1_BIT; + } + } + if (!createRenderPass()) { logError("Failed to create render pass"); return false; @@ -201,8 +217,131 @@ bool VulkanRenderer::initialize(VkDevice device, VkPhysicalDevice physicalDevice return true; } +uint32_t VulkanRenderer::getMaxUsableSampleCount() +{ + VkPhysicalDeviceProperties physicalDeviceProperties; + vkGetPhysicalDeviceProperties(m_physicalDevice, &physicalDeviceProperties); + + VkSampleCountFlags counts = physicalDeviceProperties.limits.framebufferColorSampleCounts & + physicalDeviceProperties.limits.framebufferDepthSampleCounts; + + // Try to use 4x MSAA as a good balance between quality and performance + 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; +} + +bool VulkanRenderer::createMSAAResources() +{ + std::cout << "Creating MSAA resources: " << m_width << "x" << m_height + << " with " << m_msaaSamples << " samples" << std::endl; + + VkImageCreateInfo imageInfo = {}; + imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageInfo.imageType = VK_IMAGE_TYPE_2D; + imageInfo.extent.width = m_width; + imageInfo.extent.height = m_height; + imageInfo.extent.depth = 1; + imageInfo.mipLevels = 1; + imageInfo.arrayLayers = 1; + imageInfo.format = static_cast(m_swapchainFormat); + imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageInfo.usage = VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + imageInfo.samples = static_cast(m_msaaSamples); + imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + VkResult result = vkCreateImage(m_device, &imageInfo, nullptr, &m_msaaImage); + if (result != VK_SUCCESS) { + std::cout << "Failed to create MSAA image, error: " << result << std::endl; + logError("Failed to create MSAA image"); + return false; + } + std::cout << "MSAA image created successfully" << std::endl; + + VkMemoryRequirements memRequirements; + vkGetImageMemoryRequirements(m_device, m_msaaImage, &memRequirements); + std::cout << "MSAA memory requirements: size=" << memRequirements.size + << " alignment=" << memRequirements.alignment << std::endl; + + VkMemoryAllocateInfo allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocInfo.allocationSize = memRequirements.size; + allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + + result = vkAllocateMemory(m_device, &allocInfo, nullptr, &m_msaaImageMemory); + if (result != VK_SUCCESS) { + std::cout << "Failed to allocate MSAA image memory, error: " << result << std::endl; + logError("Failed to allocate MSAA image memory"); + vkDestroyImage(m_device, m_msaaImage, nullptr); + m_msaaImage = VK_NULL_HANDLE; + return false; + } + std::cout << "MSAA memory allocated successfully" << std::endl; + + result = vkBindImageMemory(m_device, m_msaaImage, m_msaaImageMemory, 0); + if (result != VK_SUCCESS) { + std::cout << "Failed to bind MSAA image memory, error: " << result << std::endl; + logError("Failed to bind MSAA image memory"); + vkFreeMemory(m_device, m_msaaImageMemory, nullptr); + vkDestroyImage(m_device, m_msaaImage, nullptr); + m_msaaImage = VK_NULL_HANDLE; + m_msaaImageMemory = VK_NULL_HANDLE; + return false; + } + std::cout << "MSAA memory bound successfully" << std::endl; + + // Create image view + VkImageViewCreateInfo viewInfo = {}; + viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + viewInfo.image = m_msaaImage; + viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.format = static_cast(m_swapchainFormat); + viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + viewInfo.subresourceRange.baseMipLevel = 0; + viewInfo.subresourceRange.levelCount = 1; + viewInfo.subresourceRange.baseArrayLayer = 0; + viewInfo.subresourceRange.layerCount = 1; + + result = vkCreateImageView(m_device, &viewInfo, nullptr, &m_msaaImageView); + if (result != VK_SUCCESS) { + std::cout << "Failed to create MSAA image view, error: " << result << std::endl; + logError("Failed to create MSAA image view"); + vkFreeMemory(m_device, m_msaaImageMemory, nullptr); + vkDestroyImage(m_device, m_msaaImage, nullptr); + m_msaaImage = VK_NULL_HANDLE; + m_msaaImageMemory = VK_NULL_HANDLE; + return false; + } + std::cout << "MSAA image view created successfully" << std::endl; + std::cout << "MSAA resources created: image=" << m_msaaImage + << " view=" << m_msaaImageView << std::endl; + + return true; +} + +void VulkanRenderer::cleanupMSAAResources() +{ + if (m_msaaImageView != VK_NULL_HANDLE) { + vkDestroyImageView(m_device, m_msaaImageView, nullptr); + m_msaaImageView = VK_NULL_HANDLE; + } + if (m_msaaImage != VK_NULL_HANDLE) { + vkDestroyImage(m_device, m_msaaImage, nullptr); + m_msaaImage = VK_NULL_HANDLE; + } + if (m_msaaImageMemory != VK_NULL_HANDLE) { + vkFreeMemory(m_device, m_msaaImageMemory, nullptr); + m_msaaImageMemory = VK_NULL_HANDLE; + } +} + void VulkanRenderer::cleanup() { + cleanupMSAAResources(); if (!m_device) return; // Clean up buffers @@ -295,6 +434,15 @@ bool VulkanRenderer::resize(uint32_t width, uint32_t height) } m_framebuffers.clear(); + // Recreate MSAA resources if MSAA is enabled + if (m_msaaSamples > VK_SAMPLE_COUNT_1_BIT) { + cleanupMSAAResources(); + if (!createMSAAResources()) { + logError("Failed to recreate MSAA resources during resize"); + return false; + } + } + return createFramebuffers(); } @@ -396,52 +544,64 @@ void VulkanRenderer::recordCommandBuffer(VkCommandBuffer commandBuffer, return; } - // Create or get framebuffer for this image view - if (m_framebuffers.empty() || imageIndex >= m_framebuffers.size()) { - // We need to create framebuffers on-the-fly - m_imageViews.clear(); - m_imageViews.push_back(imageView); - createFramebuffers(); - } else if (imageIndex < m_imageViews.size() && m_imageViews[imageIndex] != imageView) { - // Update image view if changed - if (m_framebuffers[imageIndex]) { - vkDestroyFramebuffer(m_device, m_framebuffers[imageIndex], nullptr); - } - m_imageViews[imageIndex] = imageView; - - VkFramebufferCreateInfo fbInfo = {}; - fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - fbInfo.renderPass = m_renderPass; - fbInfo.attachmentCount = 1; - fbInfo.pAttachments = &imageView; - fbInfo.width = m_width; - fbInfo.height = m_height; - fbInfo.layers = 1; - vkCreateFramebuffer(m_device, &fbInfo, nullptr, &m_framebuffers[imageIndex]); - } - // Make sure we have enough image views while (m_imageViews.size() <= imageIndex) { m_imageViews.push_back(VK_NULL_HANDLE); } - m_imageViews[imageIndex] = imageView; // Make sure we have enough framebuffers while (m_framebuffers.size() <= imageIndex) { m_framebuffers.push_back(VK_NULL_HANDLE); } - // Create framebuffer if needed + // Check if we need to create or recreate framebuffer + bool needsRecreate = false; if (m_framebuffers[imageIndex] == VK_NULL_HANDLE) { + needsRecreate = true; + } else if (m_imageViews[imageIndex] != imageView) { + // Image view changed - destroy old framebuffer + vkDestroyFramebuffer(m_device, m_framebuffers[imageIndex], nullptr); + m_framebuffers[imageIndex] = VK_NULL_HANDLE; + needsRecreate = true; + } + + // Update image view + m_imageViews[imageIndex] = imageView; + + // Create framebuffer if needed + if (needsRecreate) { VkFramebufferCreateInfo fbInfo = {}; fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; fbInfo.renderPass = m_renderPass; - fbInfo.attachmentCount = 1; - fbInfo.pAttachments = &imageView; fbInfo.width = m_width; fbInfo.height = m_height; fbInfo.layers = 1; - vkCreateFramebuffer(m_device, &fbInfo, nullptr, &m_framebuffers[imageIndex]); + + if (m_msaaSamples > VK_SAMPLE_COUNT_1_BIT) { + // MSAA enabled: attach MSAA image and resolve image + VkImageView attachments[2] = { + m_msaaImageView, + imageView + }; + fbInfo.attachmentCount = 2; + fbInfo.pAttachments = attachments; + + static int fbCreateCount = 0; + std::cout << "Creating framebuffer " << imageIndex << " (#" << fbCreateCount++ + << ") with MSAA (msaa_view=" << m_msaaImageView + << ", resolve=" << imageView << ")" << std::endl; + } else { + // No MSAA: single attachment + fbInfo.attachmentCount = 1; + fbInfo.pAttachments = &imageView; + } + + VkResult result = vkCreateFramebuffer(m_device, &fbInfo, nullptr, &m_framebuffers[imageIndex]); + if (result != VK_SUCCESS) { + std::cout << "ERROR: Failed to create framebuffer " << imageIndex + << ", error code: " << result << std::endl; + return; + } } // Begin render pass @@ -507,43 +667,105 @@ VkFramebuffer VulkanRenderer::getFramebuffer(uint32_t index) const bool VulkanRenderer::createRenderPass() { - VkAttachmentDescription colorAttachment = {}; - colorAttachment.format = static_cast(m_swapchainFormat); - colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; - 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; + std::vector attachments; - VkAttachmentReference colorAttachmentRef = {}; - colorAttachmentRef.attachment = 0; - colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + if (m_msaaSamples > VK_SAMPLE_COUNT_1_BIT) { + // MSAA color attachment + VkAttachmentDescription colorAttachment = {}; + colorAttachment.format = static_cast(m_swapchainFormat); + colorAttachment.samples = static_cast(m_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_COLOR_ATTACHMENT_OPTIMAL; + attachments.push_back(colorAttachment); - VkSubpassDescription subpass = {}; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.colorAttachmentCount = 1; - subpass.pColorAttachments = &colorAttachmentRef; + // Resolve attachment (for presenting) + VkAttachmentDescription resolveAttachment = {}; + resolveAttachment.format = static_cast(m_swapchainFormat); + resolveAttachment.samples = VK_SAMPLE_COUNT_1_BIT; + 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; + attachments.push_back(resolveAttachment); - 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; + VkAttachmentReference colorAttachmentRef = {}; + colorAttachmentRef.attachment = 0; + colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - VkRenderPassCreateInfo renderPassInfo = {}; - renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - renderPassInfo.attachmentCount = 1; - renderPassInfo.pAttachments = &colorAttachment; - renderPassInfo.subpassCount = 1; - renderPassInfo.pSubpasses = &subpass; - renderPassInfo.dependencyCount = 1; - renderPassInfo.pDependencies = &dependency; + VkAttachmentReference resolveAttachmentRef = {}; + resolveAttachmentRef.attachment = 1; + resolveAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - return vkCreateRenderPass(m_device, &renderPassInfo, nullptr, &m_renderPass) == VK_SUCCESS; + VkSubpassDescription subpass = {}; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &colorAttachmentRef; + subpass.pResolveAttachments = &resolveAttachmentRef; + + 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; + + VkRenderPassCreateInfo renderPassInfo = {}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + renderPassInfo.attachmentCount = static_cast(attachments.size()); + renderPassInfo.pAttachments = attachments.data(); + renderPassInfo.subpassCount = 1; + renderPassInfo.pSubpasses = &subpass; + renderPassInfo.dependencyCount = 1; + renderPassInfo.pDependencies = &dependency; + + return vkCreateRenderPass(m_device, &renderPassInfo, nullptr, &m_renderPass) == VK_SUCCESS; + } else { + // No MSAA - single color attachment + VkAttachmentDescription colorAttachment = {}; + colorAttachment.format = static_cast(m_swapchainFormat); + colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; + 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; + + VkAttachmentReference colorAttachmentRef = {}; + colorAttachmentRef.attachment = 0; + colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkSubpassDescription subpass = {}; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &colorAttachmentRef; + + 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; + + VkRenderPassCreateInfo renderPassInfo = {}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + renderPassInfo.attachmentCount = 1; + renderPassInfo.pAttachments = &colorAttachment; + renderPassInfo.subpassCount = 1; + renderPassInfo.pSubpasses = &subpass; + renderPassInfo.dependencyCount = 1; + renderPassInfo.pDependencies = &dependency; + + return vkCreateRenderPass(m_device, &renderPassInfo, nullptr, &m_renderPass) == VK_SUCCESS; + } } bool VulkanRenderer::createFramebuffers() @@ -554,13 +776,33 @@ bool VulkanRenderer::createFramebuffers() VkFramebufferCreateInfo framebufferInfo = {}; framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; framebufferInfo.renderPass = m_renderPass; - framebufferInfo.attachmentCount = 1; - framebufferInfo.pAttachments = &m_imageViews[i]; framebufferInfo.width = m_width; framebufferInfo.height = m_height; framebufferInfo.layers = 1; - if (vkCreateFramebuffer(m_device, &framebufferInfo, nullptr, &m_framebuffers[i]) != VK_SUCCESS) { + if (m_msaaSamples > VK_SAMPLE_COUNT_1_BIT) { + // MSAA enabled: attach MSAA image and resolve image + if (m_msaaImageView == VK_NULL_HANDLE) { + std::cout << "ERROR: MSAA image view is null when creating framebuffer " << i << std::endl; + return false; + } + VkImageView attachments[2] = { + m_msaaImageView, + m_imageViews[i] + }; + framebufferInfo.attachmentCount = 2; + framebufferInfo.pAttachments = attachments; + std::cout << "Creating framebuffer " << i << " with MSAA (view=" << m_msaaImageView + << ", resolve=" << m_imageViews[i] << ")" << std::endl; + } else { + // No MSAA: single attachment + framebufferInfo.attachmentCount = 1; + framebufferInfo.pAttachments = &m_imageViews[i]; + } + + VkResult result = vkCreateFramebuffer(m_device, &framebufferInfo, nullptr, &m_framebuffers[i]); + if (result != VK_SUCCESS) { + std::cout << "Failed to create framebuffer " << i << ", error: " << result << std::endl; return false; } } @@ -694,7 +936,7 @@ bool VulkanRenderer::createBackgroundPipeline() 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 = static_cast(m_msaaSamples); // Color blending VkPipelineColorBlendAttachmentState colorBlendAttachment = {}; @@ -860,7 +1102,7 @@ bool VulkanRenderer::createGeometryPipeline() 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 = static_cast(m_msaaSamples); // Enable alpha blending VkPipelineColorBlendAttachmentState colorBlendAttachment = {}; @@ -1021,7 +1263,7 @@ bool VulkanRenderer::createLinePipeline() 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 = static_cast(m_msaaSamples); // Enable alpha blending VkPipelineColorBlendAttachmentState colorBlendAttachment = {}; @@ -1200,7 +1442,7 @@ bool VulkanRenderer::createTextPipeline() 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 = static_cast(m_msaaSamples); // Enable alpha blending for text VkPipelineColorBlendAttachmentState colorBlendAttachment = {}; @@ -2382,7 +2624,7 @@ void VulkanRenderer::drawText(VkCommandBuffer commandBuffer, int frameCount, // Lock info (if available) if (!lockInfo.empty()) { std::string lockTitle = "Last Lock Info:"; - generateTextQuads(lockTitle, 20.0f * scaleX, 210.0f * scaleY, 0.3f, magenta, vertices, indices); + generateTextQuads(lockTitle, 20.0f * scaleX, 220.0f * scaleY, 0.4f, magenta, vertices, indices); // Parse lock info (assuming format from lockInfo string) size_t pos = 0; @@ -2391,13 +2633,13 @@ void VulkanRenderer::drawText(VkCommandBuffer commandBuffer, int frameCount, while ((pos = info.find('\n')) != std::string::npos) { std::string token = info.substr(0, pos); if (!token.empty()) { - generateTextQuads(token, 20.0f * scaleX, (230.0f + line * 20.0f) * scaleY, 0.2f, magenta, vertices, indices); + generateTextQuads(token, 20.0f * scaleX, (240.0f + line * 20.0f) * scaleY, 0.3f, magenta, vertices, indices); line++; } info.erase(0, pos + 1); } if (!info.empty()) { - generateTextQuads(info, 20.0f * scaleX, (230.0f + line * 20.0f) * scaleY, 0.2f, magenta, vertices, indices); + generateTextQuads(info, 20.0f * scaleX, (240.0f + line * 20.0f) * scaleY, 0.3f, magenta, vertices, indices); } } diff --git a/src/vulkanrenderer.h b/src/vulkanrenderer.h index 1174ad6..2b9b337 100644 --- a/src/vulkanrenderer.h +++ b/src/vulkanrenderer.h @@ -233,6 +233,21 @@ private: */ uint32_t findMemoryType(uint32_t typeFilter, uint32_t properties); + /** + * @brief 获取最大可用的采样数 + */ + uint32_t getMaxUsableSampleCount(); + + /** + * @brief 创建多重采样图像资源 + */ + bool createMSAAResources(); + + /** + * @brief 清理多重采样资源 + */ + void cleanupMSAAResources(); + /** * @brief 初始化文本渲染系统 */ @@ -354,6 +369,12 @@ private: VkSampler m_fontSampler; std::map m_charInfoMap; + // MSAA 资源 + VkImage m_msaaImage; + VkDeviceMemory m_msaaImageMemory; + VkImageView m_msaaImageView; + uint32_t m_msaaSamples; // VkSampleCountFlagBits + // 渲染目标尺寸 uint32_t m_width; uint32_t m_height;