From 62b8a757a3f0c400f69e4439a57042be0503f4fe Mon Sep 17 00:00:00 2001 From: Kelsi Date: Fri, 3 Apr 2026 17:23:52 -0700 Subject: [PATCH] fix(rendering): skip TRANSIENT_ATTACHMENT for MSAA on GPUs without lazily allocated memory AMD RDNA4 (9070XT) crashes with SIGSEGV when MSAA is enabled because the driver optimizes TRANSIENT images for tile-only storage. Without lazily allocated memory backing, the MSAA resolve reads unbacked memory. Now we only set TRANSIENT+LAZILY_ALLOCATED when the device actually exposes that memory type. --- src/rendering/vk_context.cpp | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/rendering/vk_context.cpp b/src/rendering/vk_context.cpp index 252ef218..d83b7fec 100644 --- a/src/rendering/vk_context.cpp +++ b/src/rendering/vk_context.cpp @@ -745,6 +745,20 @@ void VkContext::destroyDepthBuffer() { bool VkContext::createMsaaColorImage() { if (msaaSamples_ == VK_SAMPLE_COUNT_1_BIT) return true; // No MSAA image needed + // Check if lazily allocated memory is available — only use TRANSIENT when it is. + // AMD GPUs (especially RDNA4) don't expose lazily allocated memory; using TRANSIENT + // without it can cause the driver to optimize for tile-only storage, leading to + // crashes during MSAA resolve when the backing memory was never populated. + bool hasLazyMemory = false; + VkPhysicalDeviceMemoryProperties memProps; + vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProps); + for (uint32_t i = 0; i < memProps.memoryTypeCount; i++) { + if (memProps.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) { + hasLazyMemory = true; + break; + } + } + VkImageCreateInfo imgInfo{}; imgInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; imgInfo.imageType = VK_IMAGE_TYPE_2D; @@ -754,11 +768,16 @@ bool VkContext::createMsaaColorImage() { imgInfo.arrayLayers = 1; imgInfo.samples = msaaSamples_; imgInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - imgInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT; VmaAllocationCreateInfo allocInfo{}; allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; - allocInfo.preferredFlags = VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT; + + if (hasLazyMemory) { + imgInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT; + allocInfo.preferredFlags = VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT; + } else { + imgInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + } if (vmaCreateImage(allocator, &imgInfo, &allocInfo, &msaaColorImage_, &msaaColorAllocation_, nullptr) != VK_SUCCESS) { // Retry without TRANSIENT (some drivers reject it at high sample counts)