diff --git a/renderdoc/driver/vulkan/vk_debug.cpp b/renderdoc/driver/vulkan/vk_debug.cpp index da73236f6..4492ddf96 100644 --- a/renderdoc/driver/vulkan/vk_debug.cpp +++ b/renderdoc/driver/vulkan/vk_debug.cpp @@ -460,6 +460,165 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver) ////////////////////////////////////////////////////////////////// // Depth MS to Array copy (via graphics) + // need a dummy UINT texture to fill the binding when we don't have a stencil aspect to copy. + // unfortunately there's no single guaranteed UINT format that can be sampled as MSAA, so we try a + // few since hopefully we'll find one that will work. + VkFormat attemptFormats[] = {VK_FORMAT_R8G8B8A8_UINT, VK_FORMAT_R8_UINT, + VK_FORMAT_S8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT, + VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D16_UNORM_S8_UINT}; + + for(VkFormat f : attemptFormats) + { + VkImageAspectFlags viewAspectMask = + IsStencilFormat(f) ? VK_IMAGE_ASPECT_STENCIL_BIT : VK_IMAGE_ASPECT_COLOR_BIT; + VkImageAspectFlags barrierAspectMask = viewAspectMask; + + if(IsDepthAndStencilFormat(f) && (barrierAspectMask & VK_IMAGE_ASPECT_STENCIL_BIT)) + barrierAspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; + + VkFormatProperties props = {}; + driver->vkGetPhysicalDeviceFormatProperties(driver->GetPhysDev(), f, &props); + + if(!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) + continue; + + VkImageCreateInfo imInfo = { + VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + NULL, + 0, + VK_IMAGE_TYPE_2D, + f, + {1, 1, 1}, + 1, + 1, + VK_SAMPLE_COUNT_1_BIT, + VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_SAMPLED_BIT, + VK_SHARING_MODE_EXCLUSIVE, + 0, + NULL, + VK_IMAGE_LAYOUT_UNDEFINED, + }; + + VkImageFormatProperties imgprops = {}; + vkr = driver->vkGetPhysicalDeviceImageFormatProperties(driver->GetPhysDev(), f, + imInfo.imageType, imInfo.tiling, + imInfo.usage, imInfo.flags, &imgprops); + + if(vkr == VK_ERROR_FORMAT_NOT_SUPPORTED) + continue; + + // if it doesn't support MSAA, bail out + if(imgprops.sampleCounts == VK_SAMPLE_COUNT_1_BIT) + continue; + + vkr = driver->vkCreateImage(driver->GetDev(), &imInfo, NULL, &m_DummyStencilImage[0]); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + rm->SetInternalResource(GetResID(m_DummyStencilImage[0])); + + imInfo.samples = VK_SAMPLE_COUNT_2_BIT; + + RDCASSERT(imgprops.sampleCounts & imInfo.samples, imgprops.sampleCounts, imInfo.samples); + + vkr = driver->vkCreateImage(driver->GetDev(), &imInfo, NULL, &m_DummyStencilImage[1]); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + rm->SetInternalResource(GetResID(m_DummyStencilImage[1])); + + VkMemoryRequirements mrq[2] = {0}; + driver->vkGetImageMemoryRequirements(driver->GetDev(), m_DummyStencilImage[0], &mrq[0]); + driver->vkGetImageMemoryRequirements(driver->GetDev(), m_DummyStencilImage[1], &mrq[1]); + + uint32_t memoryTypeBits = (mrq[0].memoryTypeBits & mrq[1].memoryTypeBits); + + // assume we have some memory type available in common + RDCASSERT(memoryTypeBits, mrq[0].memoryTypeBits, mrq[1].memoryTypeBits); + + // allocate memory + VkMemoryAllocateInfo allocInfo = { + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, NULL, + AlignUp(mrq[0].size, mrq[1].alignment) + mrq[1].size, + driver->GetGPULocalMemoryIndex(memoryTypeBits), + }; + + vkr = driver->vkAllocateMemory(driver->GetDev(), &allocInfo, NULL, &m_DummyStencilMemory); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + rm->SetInternalResource(GetResID(m_DummyStencilMemory)); + + vkr = + driver->vkBindImageMemory(driver->GetDev(), m_DummyStencilImage[0], m_DummyStencilMemory, 0); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + vkr = driver->vkBindImageMemory(driver->GetDev(), m_DummyStencilImage[1], m_DummyStencilMemory, + AlignUp(mrq[0].size, mrq[1].alignment)); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + VkImageViewCreateInfo viewInfo = { + VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + NULL, + 0, + m_DummyStencilImage[0], + VK_IMAGE_VIEW_TYPE_2D_ARRAY, + f, + {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY}, + { + viewAspectMask, 0, 1, 0, 1, + }, + }; + + vkr = driver->vkCreateImageView(driver->GetDev(), &viewInfo, NULL, &m_DummyStencilView[0]); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + rm->SetInternalResource(GetResID(m_DummyStencilView[0])); + + viewInfo.image = m_DummyStencilImage[1]; + + vkr = driver->vkCreateImageView(driver->GetDev(), &viewInfo, NULL, &m_DummyStencilView[1]); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + rm->SetInternalResource(GetResID(m_DummyStencilView[1])); + + VkCommandBuffer cmd = driver->GetNextCmd(); + + VkCommandBufferBeginInfo beginInfo = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, NULL, + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT}; + + vkr = ObjDisp(cmd)->BeginCommandBuffer(Unwrap(cmd), &beginInfo); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + // need to update image layout into valid state + VkImageMemoryBarrier barrier = { + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + NULL, + 0, + VK_ACCESS_SHADER_READ_BIT, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_QUEUE_FAMILY_IGNORED, + VK_QUEUE_FAMILY_IGNORED, + Unwrap(m_DummyStencilImage[0]), + {barrierAspectMask, 0, 1, 0, 1}, + }; + + DoPipelineBarrier(cmd, 1, &barrier); + + barrier.image = Unwrap(m_DummyStencilImage[1]); + + DoPipelineBarrier(cmd, 1, &barrier); + + ObjDisp(cmd)->EndCommandBuffer(Unwrap(cmd)); + + break; + } + + if(m_DummyStencilImage[0] == VK_NULL_HANDLE) + { + RDCERR("Couldn't find any integer format we could generate a dummy multisampled image with"); + } + CREATE_OBJECT(m_ArrayMSDescSet, m_ArrayMSDescriptorPool, m_ArrayMSDescSetLayout); rm->SetInternalResource(GetResID(m_ArrayMSDescSet)); @@ -570,6 +729,12 @@ VulkanDebugManager::~VulkanDebugManager() m_pDriver->vkDestroyDescriptorPool(dev, m_ArrayMSDescriptorPool, NULL); m_pDriver->vkDestroySampler(dev, m_ArrayMSSampler, NULL); + m_pDriver->vkDestroyImageView(dev, m_DummyStencilView[0], NULL); + m_pDriver->vkDestroyImageView(dev, m_DummyStencilView[1], NULL); + m_pDriver->vkDestroyImage(dev, m_DummyStencilImage[0], NULL); + m_pDriver->vkDestroyImage(dev, m_DummyStencilImage[1], NULL); + m_pDriver->vkFreeMemory(dev, m_DummyStencilMemory, NULL); + m_pDriver->vkDestroyDescriptorSetLayout(dev, m_ArrayMSDescSetLayout, NULL); m_pDriver->vkDestroyPipelineLayout(dev, m_ArrayMSPipeLayout, NULL); m_pDriver->vkDestroyPipeline(dev, m_Array2MSPipe, NULL); diff --git a/renderdoc/driver/vulkan/vk_debug.h b/renderdoc/driver/vulkan/vk_debug.h index 5ce7a187f..ba157d27d 100644 --- a/renderdoc/driver/vulkan/vk_debug.h +++ b/renderdoc/driver/vulkan/vk_debug.h @@ -97,6 +97,11 @@ private: VkSampler m_ArrayMSSampler = VK_NULL_HANDLE; + // [0] = non-MSAA, [1] = MSAA + VkDeviceMemory m_DummyStencilMemory = VK_NULL_HANDLE; + VkImage m_DummyStencilImage[2] = {VK_NULL_HANDLE}; + VkImageView m_DummyStencilView[2] = {VK_NULL_HANDLE}; + // one per depth/stencil output format VkPipeline m_DepthMS2ArrayPipe[6] = {VK_NULL_HANDLE}; // one per depth/stencil output format, per sample count diff --git a/renderdoc/driver/vulkan/vk_msaa_array_conv.cpp b/renderdoc/driver/vulkan/vk_msaa_array_conv.cpp index 531ff1fb1..ad1d3383b 100644 --- a/renderdoc/driver/vulkan/vk_msaa_array_conv.cpp +++ b/renderdoc/driver/vulkan/vk_msaa_array_conv.cpp @@ -232,6 +232,21 @@ void VulkanDebugManager::CopyDepthTex2DMSToArray(VkImage destArray, VkImage srcM srcdesc[1].imageView = srcStencilView; srcdesc[1].sampler = Unwrap(m_ArrayMSSampler); // not used - we use texelFetch + if((aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) == 0) + { + if(m_DummyStencilView[1] != VK_NULL_HANDLE) + { + srcdesc[1].imageView = Unwrap(m_DummyStencilView[1]); + } + else + { + // as a last fallback, hope that setting an incompatible view (float not int) will not break + // too badly. This only gets hit when the implementation has such poor format support that + // there are no uint formats that can be sampled as MSAA. + srcdesc[1].imageView = srcDepthView; + } + } + VkWriteDescriptorSet writeSet[] = { {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_ArrayMSDescSet), 0, 0, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &srcdesc[0], NULL, NULL}, @@ -239,10 +254,7 @@ void VulkanDebugManager::CopyDepthTex2DMSToArray(VkImage destArray, VkImage srcM VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &srcdesc[1], NULL, NULL}, }; - if(aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) - ObjDisp(dev)->UpdateDescriptorSets(Unwrap(dev), 2, writeSet, 0, NULL); - else - ObjDisp(dev)->UpdateDescriptorSets(Unwrap(dev), 1, writeSet, 0, NULL); + ObjDisp(dev)->UpdateDescriptorSets(Unwrap(dev), 2, writeSet, 0, NULL); // create a bespoke framebuffer and renderpass for rendering VkAttachmentDescription attDesc = {0, @@ -583,6 +595,21 @@ void VulkanDebugManager::CopyDepthArrayToTex2DMS(VkImage destMS, VkImage srcArra srcdesc[1].imageView = srcStencilView; srcdesc[1].sampler = Unwrap(m_ArrayMSSampler); // not used - we use texelFetch + if((aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) == 0) + { + if(m_DummyStencilView[0] != VK_NULL_HANDLE) + { + srcdesc[1].imageView = Unwrap(m_DummyStencilView[0]); + } + else + { + // as a last fallback, hope that setting an incompatible view (float not int) will not break + // too badly. This only gets hit when the implementation has such poor format support that + // there are no uint formats that can be sampled as MSAA. + srcdesc[1].imageView = srcDepthView; + } + } + VkWriteDescriptorSet writeSet[] = { {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, NULL, Unwrap(m_ArrayMSDescSet), 0, 0, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &srcdesc[0], NULL, NULL}, @@ -590,10 +617,7 @@ void VulkanDebugManager::CopyDepthArrayToTex2DMS(VkImage destMS, VkImage srcArra VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &srcdesc[1], NULL, NULL}, }; - if(aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) - ObjDisp(dev)->UpdateDescriptorSets(Unwrap(dev), 2, writeSet, 0, NULL); - else - ObjDisp(dev)->UpdateDescriptorSets(Unwrap(dev), 1, writeSet, 0, NULL); + ObjDisp(dev)->UpdateDescriptorSets(Unwrap(dev), 2, writeSet, 0, NULL); // create a bespoke framebuffer and renderpass for rendering VkAttachmentDescription attDesc = {0, diff --git a/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp index 93308dc30..b082f4041 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp @@ -1471,7 +1471,9 @@ VkResult WrappedVulkan::vkCreateImage(VkDevice device, const VkImageCreateInfo * { if(!IsDepthOrStencilFormat(createInfo_adjusted.format)) { - if(GetDebugManager()->IsMS2ArraySupported()) + // need to check the debug manager here since we might be creating this internal image from + // its constructor + if(GetDebugManager() && GetDebugManager()->IsMS2ArraySupported()) createInfo_adjusted.usage |= VK_IMAGE_USAGE_STORAGE_BIT; } else