Compare commits

...

2 Commits

Author SHA1 Message Date
ubuntu1804 d82fc95584 优化 MSAA 2025-11-10 21:51:11 +08:00
ubuntu1804 2f16c0b5e4 add msaa 2025-11-10 21:43:42 +08:00
3 changed files with 383 additions and 75 deletions

View File

@ -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,154 @@ 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;
std::cout << "Available MSAA sample counts: ";
if (counts & VK_SAMPLE_COUNT_64_BIT) std::cout << "64 ";
if (counts & VK_SAMPLE_COUNT_32_BIT) std::cout << "32 ";
if (counts & VK_SAMPLE_COUNT_16_BIT) std::cout << "16 ";
if (counts & VK_SAMPLE_COUNT_8_BIT) std::cout << "8 ";
if (counts & VK_SAMPLE_COUNT_4_BIT) std::cout << "4 ";
if (counts & VK_SAMPLE_COUNT_2_BIT) std::cout << "2 ";
std::cout << std::endl;
// Prefer higher sample counts for better quality
if (counts & VK_SAMPLE_COUNT_16_BIT) {
std::cout << "Selected: 16x MSAA" << std::endl;
return VK_SAMPLE_COUNT_16_BIT;
}
if (counts & VK_SAMPLE_COUNT_8_BIT) {
std::cout << "Selected: 8x MSAA" << std::endl;
return VK_SAMPLE_COUNT_8_BIT;
}
if (counts & VK_SAMPLE_COUNT_4_BIT) {
std::cout << "Selected: 4x MSAA" << std::endl;
return VK_SAMPLE_COUNT_4_BIT;
}
if (counts & VK_SAMPLE_COUNT_2_BIT) {
std::cout << "Selected: 2x MSAA" << std::endl;
return VK_SAMPLE_COUNT_2_BIT;
}
std::cout << "No MSAA support available" << std::endl;
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<VkFormat>(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<VkSampleCountFlagBits>(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<VkFormat>(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 +457,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 +567,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 +690,105 @@ VkFramebuffer VulkanRenderer::getFramebuffer(uint32_t index) const
bool VulkanRenderer::createRenderPass()
{
VkAttachmentDescription colorAttachment = {};
colorAttachment.format = static_cast<VkFormat>(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<VkAttachmentDescription> 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<VkFormat>(m_swapchainFormat);
colorAttachment.samples = static_cast<VkSampleCountFlagBits>(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<VkFormat>(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<uint32_t>(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<VkFormat>(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 +799,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;
}
}
@ -693,8 +958,9 @@ bool VulkanRenderer::createBackgroundPipeline()
// Multisampling
VkPipelineMultisampleStateCreateInfo multisampling = {};
multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampling.sampleShadingEnable = VK_FALSE;
multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
multisampling.sampleShadingEnable = VK_TRUE; // Enable sample shading for better quality
multisampling.minSampleShading = 0.5f; // Minimum fraction for sample shading
multisampling.rasterizationSamples = static_cast<VkSampleCountFlagBits>(m_msaaSamples);
// Color blending
VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
@ -859,8 +1125,9 @@ 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.sampleShadingEnable = VK_TRUE; // Enable sample shading for better quality
multisampling.minSampleShading = 0.5f; // Minimum fraction for sample shading
multisampling.rasterizationSamples = static_cast<VkSampleCountFlagBits>(m_msaaSamples);
// Enable alpha blending
VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
@ -1020,8 +1287,9 @@ 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.sampleShadingEnable = VK_TRUE; // Enable sample shading for smoother lines
multisampling.minSampleShading = 0.75f; // Higher quality for lines
multisampling.rasterizationSamples = static_cast<VkSampleCountFlagBits>(m_msaaSamples);
// Enable alpha blending
VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
@ -1199,8 +1467,9 @@ 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.sampleShadingEnable = VK_TRUE; // Enable sample shading for smoother text
multisampling.minSampleShading = 1.0f; // Maximum quality for text rendering
multisampling.rasterizationSamples = static_cast<VkSampleCountFlagBits>(m_msaaSamples);
// Enable alpha blending for text
VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
@ -2382,7 +2651,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 +2660,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);
}
}

View File

@ -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<char, CharInfo> 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;

View File

@ -359,7 +359,25 @@ bool VulkanWidget::createDevice()
queueCreateInfo.queueCount = 1;
queueCreateInfo.pQueuePriorities = &queuePriority;
// Query supported features first
VkPhysicalDeviceFeatures supportedFeatures;
vkGetPhysicalDeviceFeatures(m_physicalDevice, &supportedFeatures);
VkPhysicalDeviceFeatures deviceFeatures = {};
// Enable sample rate shading for better MSAA quality
if (supportedFeatures.sampleRateShading) {
deviceFeatures.sampleRateShading = VK_TRUE;
qDebug() << "Sample rate shading feature enabled";
} else {
qDebug() << "Sample rate shading not supported by device";
}
// Enable wide lines if supported (for smoother line rendering)
if (supportedFeatures.wideLines) {
deviceFeatures.wideLines = VK_TRUE;
qDebug() << "Wide lines feature enabled";
}
std::vector<const char*> deviceExtensions = getRequiredDeviceExtensions();