diff --git a/renderdoc/driver/vulkan/vk_debug.cpp b/renderdoc/driver/vulkan/vk_debug.cpp index b14c111b6..3ccf331e8 100644 --- a/renderdoc/driver/vulkan/vk_debug.cpp +++ b/renderdoc/driver/vulkan/vk_debug.cpp @@ -195,6 +195,14 @@ static void create(WrappedVulkan *driver, const char *objName, const int line, RDCERR("Failed creating object %s at line %i, vkr was %s", objName, line, ToStr(vkr).c_str()); } +enum class StencilMode +{ + KEEP, + KEEP_TEST_EQUAL_ONE, + REPLACE, + WRITE_ZERO, +}; + // a simpler one-shot descriptor containing anything we might want to vary in a graphics pipeline struct ConciseGraphicsPipeline { @@ -214,7 +222,7 @@ struct ConciseGraphicsPipeline // depth stencil bool depthEnable; bool stencilEnable; - VkStencilOp stencilOp; + StencilMode stencilOperations; // color blend bool colourOutput; @@ -260,6 +268,34 @@ static void create(WrappedVulkan *driver, const char *objName, const int line, V msaa.sampleShadingEnable = true; } + VkCompareOp stencilTest = VK_COMPARE_OP_ALWAYS; + VkStencilOp stencilOp = VK_STENCIL_OP_KEEP; + uint8_t stencilReference = 0; + + switch(info.stencilOperations) + { + case StencilMode::KEEP: + { + break; + } + case StencilMode::KEEP_TEST_EQUAL_ONE: + { + stencilTest = VK_COMPARE_OP_EQUAL; + stencilReference = 1; + break; + } + case StencilMode::REPLACE: + { + stencilOp = VK_STENCIL_OP_REPLACE; + break; + } + case StencilMode::WRITE_ZERO: + { + stencilOp = VK_STENCIL_OP_ZERO; + break; + } + }; + const VkPipelineDepthStencilStateCreateInfo depthStencil = { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, NULL, @@ -269,8 +305,8 @@ static void create(WrappedVulkan *driver, const char *objName, const int line, V VK_COMPARE_OP_ALWAYS, false, info.stencilEnable, - {info.stencilOp, info.stencilOp, info.stencilOp, VK_COMPARE_OP_ALWAYS, 0xff, 0xff, 0}, - {info.stencilOp, info.stencilOp, info.stencilOp, VK_COMPARE_OP_ALWAYS, 0xff, 0xff, 0}, + {stencilOp, stencilOp, stencilOp, stencilTest, 0xff, 0xff, stencilReference}, + {stencilOp, stencilOp, stencilOp, stencilTest, 0xff, 0xff, stencilReference}, 0.0f, 1.0f, }; @@ -686,7 +722,7 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver) true, // sampleRateShading true, // depthEnable true, // stencilEnable - VK_STENCIL_OP_REPLACE, + StencilMode::REPLACE, false, // colourOutput false, // blendEnable VK_BLEND_FACTOR_ONE, @@ -738,7 +774,7 @@ VulkanDebugManager::VulkanDebugManager(WrappedVulkan *driver) false, // sampleRateShading false, // depthEnable false, // stencilEnable - VK_STENCIL_OP_REPLACE, + StencilMode::REPLACE, true, // colourOutput false, // blendEnable VK_BLEND_FACTOR_ONE, @@ -1079,7 +1115,7 @@ void VulkanDebugManager::CreateCustomShaderPipeline(ResourceId shader, VkPipelin false, // sampleRateShading false, // depthEnable false, // stencilEnable - VK_STENCIL_OP_KEEP, + StencilMode::KEEP, true, // colourOutput false, // blendEnable VK_BLEND_FACTOR_ONE, @@ -2094,7 +2130,7 @@ void VulkanDebugManager::FillWithDiscardPattern(VkCommandBuffer cmd, DiscardType false, // sampleRateShading true, // depthEnable true, // stencilEnable - VK_STENCIL_OP_REPLACE, + StencilMode::REPLACE, true, // colourOutput false, // blendEnable VK_BLEND_FACTOR_ONE, @@ -3393,7 +3429,7 @@ void VulkanReplay::TextureRendering::Init(WrappedVulkan *driver, VkDescriptorPoo false, // sampleRateShading false, // depthEnable false, // stencilEnable - VK_STENCIL_OP_KEEP, + StencilMode::KEEP, true, // colourOutput false, // blendEnable VK_BLEND_FACTOR_ONE, @@ -3840,6 +3876,8 @@ void VulkanReplay::OverlayRendering::Init(WrappedVulkan *driver, VkDescriptorPoo CREATE_OBJECT(SRGBA8RP, VK_FORMAT_R8G8B8A8_SRGB); CREATE_OBJECT(SRGBA8MSRP, VK_FORMAT_R8G8B8A8_SRGB, VULKAN_MESH_VIEW_SAMPLES); + CREATE_OBJECT(m_PointSampler, VK_FILTER_NEAREST); + CREATE_OBJECT(m_CheckerDescSetLayout, {{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_ALL, NULL}}); @@ -3854,12 +3892,24 @@ void VulkanReplay::OverlayRendering::Init(WrappedVulkan *driver, VkDescriptorPoo {2, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_ALL, NULL}, }); + CREATE_OBJECT(m_DepthCopyDescSetLayout, { + { + 0, + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + 1, + VK_SHADER_STAGE_ALL, + &m_PointSampler, + }, + }); + CREATE_OBJECT(m_CheckerPipeLayout, m_CheckerDescSetLayout, 0); CREATE_OBJECT(m_QuadResolvePipeLayout, m_QuadDescSetLayout, 0); CREATE_OBJECT(m_TriSizePipeLayout, m_TriSizeDescSetLayout, 0); + CREATE_OBJECT(m_DepthCopyPipeLayout, m_DepthCopyDescSetLayout, 0); CREATE_OBJECT(m_QuadDescSet, descriptorPool, m_QuadDescSetLayout); CREATE_OBJECT(m_TriSizeDescSet, descriptorPool, m_TriSizeDescSetLayout); CREATE_OBJECT(m_CheckerDescSet, descriptorPool, m_CheckerDescSetLayout); + CREATE_OBJECT(m_DepthCopyDescSet, descriptorPool, m_DepthCopyDescSetLayout); m_CheckerUBO.Create(driver, driver->GetDev(), 128, 10, 0); RDCCOMPILE_ASSERT(sizeof(CheckerboardUBOData) <= 128, "checkerboard UBO size"); @@ -3876,7 +3926,7 @@ void VulkanReplay::OverlayRendering::Init(WrappedVulkan *driver, VkDescriptorPoo false, // sampleRateShading false, // depthEnable false, // stencilEnable - VK_STENCIL_OP_KEEP, + StencilMode::KEEP, true, // colourOutput false, // blendEnable VK_BLEND_FACTOR_SRC_ALPHA, @@ -3914,7 +3964,7 @@ void VulkanReplay::OverlayRendering::Init(WrappedVulkan *driver, VkDescriptorPoo else continue; - // if we this sample count is supported then create a pipeline + // if we know this sample count is supported then create a pipeline pipeInfo.renderPass = RGBA16MSRP; pipeInfo.sampleCount = VkSampleCountFlagBits(1 << i); @@ -3939,9 +3989,260 @@ void VulkanReplay::OverlayRendering::Init(WrappedVulkan *driver, VkDescriptorPoo driver->vkDestroyRenderPass(driver->GetDev(), RGBA16MSRP, NULL); } + samplesHandled = 0; + { + ConciseGraphicsPipeline DepthCopyPipeInfo = { + SRGBA8RP, + m_DepthCopyPipeLayout, + shaderCache->GetBuiltinModule(BuiltinShader::BlitVS), + shaderCache->GetBuiltinModule(BuiltinShader::DepthCopyFS), + {VK_DYNAMIC_STATE_VIEWPORT}, + VK_SAMPLE_COUNT_1_BIT, + false, // sampleRateShading + true, // depthEnable + true, // stencilEnable + StencilMode::WRITE_ZERO, + true, // colourOutput + false, // blendEnable + VK_BLEND_FACTOR_DST_ALPHA, + VK_BLEND_FACTOR_ONE, + 0x0, // writeMask + }; + + VkAttachmentReference colRef = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; + VkAttachmentReference dsRef = {1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}; + + VkAttachmentDescription attDescs[] = { + { + 0, + VK_FORMAT_R16G16B16A16_SFLOAT, + VK_SAMPLE_COUNT_1_BIT, + VK_ATTACHMENT_LOAD_OP_LOAD, + VK_ATTACHMENT_STORE_OP_STORE, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, + VK_ATTACHMENT_STORE_OP_DONT_CARE, + colRef.layout, + colRef.layout, + }, + { + 0, + VK_FORMAT_D24_UNORM_S8_UINT, + VK_SAMPLE_COUNT_1_BIT, // will patch this just below + VK_ATTACHMENT_LOAD_OP_DONT_CARE, + VK_ATTACHMENT_STORE_OP_STORE, + VK_ATTACHMENT_LOAD_OP_CLEAR, + VK_ATTACHMENT_STORE_OP_STORE, + dsRef.layout, + dsRef.layout, + }, + }; + + VkSubpassDescription subp = { + 0, VK_PIPELINE_BIND_POINT_GRAPHICS, + 0, NULL, // inputs + 1, &colRef, // color + NULL, // resolve + &dsRef, // depth-stencil + 0, NULL, // preserve + }; + + VkRenderPassCreateInfo rpinfo = { + VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + NULL, + 0, + 2, + attDescs, + 1, + &subp, + 0, + NULL, // dependencies + }; + + RDCCOMPILE_ASSERT(ARRAY_COUNT(m_DepthResolvePipeline) == ARRAY_COUNT(m_DepthResolvePipeline), + "m_DepthCopyPipeline size must match m_DepthResolvePipeline"); + + if(DepthCopyPipeInfo.fragment != VK_NULL_HANDLE) + { + for(size_t f = 0; f < ARRAY_COUNT(m_DepthCopyPipeline); ++f) + { + VkFormat fmt = (f == 0) ? VK_FORMAT_D24_UNORM_S8_UINT : VK_FORMAT_D32_SFLOAT_S8_UINT; + attDescs[1].format = fmt; + for(size_t i = 0; i < ARRAY_COUNT(m_DepthCopyPipeline[f]); ++i) + { + m_DepthCopyPipeline[f][i] = VK_NULL_HANDLE; + VkSampleCountFlagBits samples = VkSampleCountFlagBits(1 << i); + + if((supportedSampleCounts & (uint32_t)samples) == 0) + continue; + + VkRenderPass depthMSRP = VK_NULL_HANDLE; + attDescs[0].samples = samples; + attDescs[1].samples = samples; + VkResult vkr = driver->vkCreateRenderPass(driver->GetDev(), &rpinfo, NULL, &depthMSRP); + if(vkr != VK_SUCCESS) + RDCERR("Failed to create depth overlay resolve render pass: %s", ToStr(vkr).c_str()); + + if(depthMSRP != VK_NULL_HANDLE) + samplesHandled |= (uint32_t)samples; + else + continue; + + // if we know this sample count is supported then create a pipeline + DepthCopyPipeInfo.renderPass = depthMSRP; + DepthCopyPipeInfo.sampleCount = VkSampleCountFlagBits(1 << i); + + if(i == 0) + DepthCopyPipeInfo.fragment = shaderCache->GetBuiltinModule(BuiltinShader::DepthCopyFS); + else + DepthCopyPipeInfo.fragment = shaderCache->GetBuiltinModule(BuiltinShader::DepthCopyMSFS); + + CREATE_OBJECT(m_DepthCopyPipeline[f][i], DepthCopyPipeInfo); + + driver->vkDestroyRenderPass(driver->GetDev(), depthMSRP, NULL); + } + } + } + } RDCASSERTEQUAL((uint32_t)driver->GetDeviceProps().limits.framebufferColorSampleCounts, samplesHandled); + samplesHandled = 0; + { + // make patched shader + VkShaderModule greenFSmod = VK_NULL_HANDLE; + float green[] = {0.0f, 1.0f, 0.0f, 1.0f}; + driver->GetDebugManager()->PatchFixedColShader(greenFSmod, green); + + CREATE_OBJECT(m_DepthResolvePipeLayout, VK_NULL_HANDLE, 0); + + ConciseGraphicsPipeline DepthResolvePipeInfo = { + SRGBA8RP, + m_DepthResolvePipeLayout, + shaderCache->GetBuiltinModule(BuiltinShader::BlitVS), + greenFSmod, + {VK_DYNAMIC_STATE_VIEWPORT}, + VK_SAMPLE_COUNT_1_BIT, + false, // sampleRateShading + false, // depthEnable + true, // stencilEnable + StencilMode::KEEP_TEST_EQUAL_ONE, + true, // colourOutput + false, // blendEnable + VK_BLEND_FACTOR_DST_ALPHA, + VK_BLEND_FACTOR_ONE, + 0xf, // writeMask + }; + + VkAttachmentReference colRef = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; + VkAttachmentReference dsRef = {1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}; + + VkAttachmentDescription attDescs[] = { + { + 0, + VK_FORMAT_R16G16B16A16_SFLOAT, + VK_SAMPLE_COUNT_1_BIT, + VK_ATTACHMENT_LOAD_OP_LOAD, + VK_ATTACHMENT_STORE_OP_STORE, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, + VK_ATTACHMENT_STORE_OP_DONT_CARE, + colRef.layout, + colRef.layout, + }, + { + 0, + VK_FORMAT_D24_UNORM_S8_UINT, + VK_SAMPLE_COUNT_1_BIT, // will patch this just below + VK_ATTACHMENT_LOAD_OP_LOAD, + VK_ATTACHMENT_STORE_OP_STORE, + VK_ATTACHMENT_LOAD_OP_LOAD, + VK_ATTACHMENT_STORE_OP_STORE, + dsRef.layout, + dsRef.layout, + }, + }; + + VkSubpassDescription subp = { + 0, VK_PIPELINE_BIND_POINT_GRAPHICS, + 0, NULL, // inputs + 1, &colRef, // color + NULL, // resolve + &dsRef, // depth-stencil + 0, NULL, // preserve + }; + + VkRenderPassCreateInfo rpinfo = { + VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + NULL, + 0, + 2, + attDescs, + 1, + &subp, + 0, + NULL, // dependencies + }; + + if(DepthResolvePipeInfo.fragment != VK_NULL_HANDLE) + { + for(size_t f = 0; f < ARRAY_COUNT(m_DepthResolvePipeline); ++f) + { + VkFormat fmt = (f == 0) ? VK_FORMAT_D24_UNORM_S8_UINT : VK_FORMAT_D32_SFLOAT_S8_UINT; + attDescs[1].format = fmt; + for(size_t i = 0; i < ARRAY_COUNT(m_DepthResolvePipeline[f]); ++i) + { + m_DepthResolvePipeline[f][i] = VK_NULL_HANDLE; + VkSampleCountFlagBits samples = VkSampleCountFlagBits(1 << i); + + if((supportedSampleCounts & (uint32_t)samples) == 0) + continue; + + VkRenderPass rgba16MSRP = VK_NULL_HANDLE; + attDescs[0].samples = samples; + attDescs[1].samples = samples; + VkResult vkr = driver->vkCreateRenderPass(driver->GetDev(), &rpinfo, NULL, &rgba16MSRP); + if(vkr != VK_SUCCESS) + RDCERR("Failed to create depth overlay resolve render pass: %s", ToStr(vkr).c_str()); + + if(rgba16MSRP != VK_NULL_HANDLE) + samplesHandled |= (uint32_t)samples; + else + continue; + + // if we know this sample count is supported then create a pipeline + DepthResolvePipeInfo.renderPass = rgba16MSRP; + DepthResolvePipeInfo.sampleCount = VkSampleCountFlagBits(1 << i); + + CREATE_OBJECT(m_DepthResolvePipeline[f][i], DepthResolvePipeInfo); + + driver->vkDestroyRenderPass(driver->GetDev(), rgba16MSRP, NULL); + } + } + } + } + + RDCASSERTEQUAL((uint32_t)driver->GetDeviceProps().limits.framebufferColorSampleCounts, + samplesHandled); + + m_DefaultDepthStencilFormat = VK_FORMAT_UNDEFINED; + { + for(VkFormat fmt : {VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT}) + { + VkImageFormatProperties imgprops = {}; + VkResult vkr = driver->vkGetPhysicalDeviceImageFormatProperties( + driver->GetPhysDev(), fmt, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, 0, &imgprops); + if(vkr == VK_SUCCESS) + { + m_DefaultDepthStencilFormat = fmt; + break; + } + } + } + if(m_DefaultDepthStencilFormat == VK_FORMAT_UNDEFINED) + { + RDCERR("Overlay failed to find default depth stencil format"); + } + VkDescriptorBufferInfo checkerboard = {}; m_CheckerUBO.FillDescriptor(checkerboard); @@ -3974,6 +4275,19 @@ void VulkanReplay::OverlayRendering::Destroy(WrappedVulkan *driver) for(size_t i = 0; i < ARRAY_COUNT(m_QuadResolvePipeline); i++) driver->vkDestroyPipeline(driver->GetDev(), m_QuadResolvePipeline[i], NULL); + driver->vkDestroyPipelineLayout(driver->GetDev(), m_DepthResolvePipeLayout, NULL); + driver->vkDestroyDescriptorSetLayout(driver->GetDev(), m_DepthCopyDescSetLayout, NULL); + driver->vkDestroyPipelineLayout(driver->GetDev(), m_DepthCopyPipeLayout, NULL); + + for(size_t f = 0; f < ARRAY_COUNT(m_DepthResolvePipeline); ++f) + { + for(size_t i = 0; i < ARRAY_COUNT(m_DepthResolvePipeline[f]); ++i) + { + driver->vkDestroyPipeline(driver->GetDev(), m_DepthResolvePipeline[f][i], NULL); + driver->vkDestroyPipeline(driver->GetDev(), m_DepthCopyPipeline[f][i], NULL); + } + } + driver->vkDestroyDescriptorSetLayout(driver->GetDev(), m_CheckerDescSetLayout, NULL); driver->vkDestroyPipelineLayout(driver->GetDev(), m_CheckerPipeLayout, NULL); for(size_t i = 0; i < ARRAY_COUNT(m_CheckerF16Pipeline); i++) @@ -3986,6 +4300,8 @@ void VulkanReplay::OverlayRendering::Destroy(WrappedVulkan *driver) m_TriSizeUBO.Destroy(); driver->vkDestroyDescriptorSetLayout(driver->GetDev(), m_TriSizeDescSetLayout, NULL); driver->vkDestroyPipelineLayout(driver->GetDev(), m_TriSizePipeLayout, NULL); + + driver->vkDestroySampler(driver->GetDev(), m_PointSampler, NULL); } void VulkanReplay::MeshRendering::Init(WrappedVulkan *driver, VkDescriptorPool descriptorPool) diff --git a/renderdoc/driver/vulkan/vk_overlay.cpp b/renderdoc/driver/vulkan/vk_overlay.cpp index c624fe093..c89408edb 100644 --- a/renderdoc/driver/vulkan/vk_overlay.cpp +++ b/renderdoc/driver/vulkan/vk_overlay.cpp @@ -1189,7 +1189,6 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, D RemoveNextStruct(&pipeCreateInfo, VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO); VkPipelineShaderStageCreateInfo *fragShader = NULL; - for(uint32_t i = 0; i < pipeCreateInfo.stageCount; i++) { VkPipelineShaderStageCreateInfo &sh = @@ -1567,6 +1566,9 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, D } else if(overlay == DebugOverlay::Depth || overlay == DebugOverlay::Stencil) { + VkImage dsImage = VK_NULL_HANDLE; + VkDeviceMemory dsImageMem = VK_NULL_HANDLE; + float highlightCol[] = {0.0f, 0.0f, 0.0f, 0.0f}; VkImageMemoryBarrier barrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, @@ -1595,6 +1597,7 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, D { vkr = vt->EndCommandBuffer(Unwrap(cmd)); CheckVkResult(vkr); + cmd = VK_NULL_HANDLE; VkFramebuffer depthFB = VK_NULL_HANDLE; VkRenderPass depthRP = VK_NULL_HANDLE; @@ -1602,6 +1605,7 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, D VulkanCreationInfo &createinfo = m_pDriver->m_CreationInfo; ResourceId depthStencilView; + VkFormat dsFmt = VK_FORMAT_UNDEFINED; if(state.dynamicRendering.active) { @@ -1624,8 +1628,17 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, D } } + bool useDepthWriteStencilPass = false; + bool needDepthCopyToDepthStencil = false; + + size_t fmtIndex = ARRAY_COUNT(m_Overlay.m_DepthCopyPipeline); + size_t sampleIndex = SampleIndex(iminfo.samples); + if(depthStencilView != ResourceId()) { + if(overlay == DebugOverlay::Depth) + useDepthWriteStencilPass = true; + VkAttachmentDescription attDescs[] = { {0, overlayFormat, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, @@ -1642,7 +1655,41 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, D ResourceId depthIm = depthViewInfo.image; VulkanCreationInfo::Image &depthImageInfo = createinfo.m_Image[depthIm]; - attDescs[1].format = depthImageInfo.format; + dsFmt = depthImageInfo.format; + VkFormat dsNewFmt = dsFmt; + if(useDepthWriteStencilPass) + { + if(dsFmt == VK_FORMAT_D32_SFLOAT_S8_UINT) + dsNewFmt = VK_FORMAT_D32_SFLOAT_S8_UINT; + else if(dsFmt == VK_FORMAT_D24_UNORM_S8_UINT) + dsNewFmt = VK_FORMAT_D24_UNORM_S8_UINT; + else if(dsFmt == VK_FORMAT_D32_SFLOAT) + dsNewFmt = VK_FORMAT_D32_SFLOAT_S8_UINT; + else if(dsFmt == VK_FORMAT_D16_UNORM) + dsNewFmt = m_Overlay.m_DefaultDepthStencilFormat; + else + dsNewFmt = m_Overlay.m_DefaultDepthStencilFormat; + + RDCASSERT((dsNewFmt == VK_FORMAT_D24_UNORM_S8_UINT) || + (dsNewFmt == VK_FORMAT_D32_SFLOAT_S8_UINT)); + fmtIndex = (dsNewFmt == VK_FORMAT_D24_UNORM_S8_UINT) ? 0 : 1; + if(m_Overlay.m_DepthResolvePipeline[fmtIndex][sampleIndex] == 0) + { + RDCERR("Unhandled depth resolve format : %s", ToStr(dsNewFmt).c_str()); + return ResourceId(); + } + if(dsNewFmt != dsFmt) + { + needDepthCopyToDepthStencil = true; + if(m_Overlay.m_DepthCopyPipeline[fmtIndex][sampleIndex] == 0) + { + RDCERR("Unhandled depth copy format : %s", ToStr(dsNewFmt).c_str()); + return ResourceId(); + } + } + } + + attDescs[1].format = dsNewFmt; attDescs[0].samples = attDescs[1].samples = iminfo.samples; { @@ -1688,9 +1735,144 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, D vkr = m_pDriver->vkCreateRenderPass(m_Device, &rpinfo, NULL, &depthRP); CheckVkResult(vkr); + VkImageView dsView = + m_pDriver->GetResourceManager()->GetCurrentHandle(depthStencilView); + + if(needDepthCopyToDepthStencil) + { + VkImageSubresourceRange dsSubRange = { + VK_IMAGE_ASPECT_DEPTH_BIT, sub.mip, 1, sub.slice, sub.numSlices, + }; + + VkImage dsRealImage = m_pDriver->GetResourceManager()->GetCurrentHandle(depthIm); + VkImageViewCreateInfo dsViewInfo = { + VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + NULL, + 0, + dsRealImage, + VK_IMAGE_VIEW_TYPE_2D, + dsFmt, + {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY}, + dsSubRange, + }; + + vkr = m_pDriver->vkCreateImageView(m_Device, &dsViewInfo, NULL, &dsView); + + // update descriptor to point to copy of original depth buffer + VkDescriptorImageInfo imdesc = {0}; + imdesc.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + imdesc.sampler = VK_NULL_HANDLE; + imdesc.imageView = Unwrap(dsView); + + VkWriteDescriptorSet write = { + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + NULL, + Unwrap(m_Overlay.m_DepthCopyDescSet), + 0, + 0, + 1, + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + &imdesc, + NULL, + NULL, + }; + vt->UpdateDescriptorSets(Unwrap(m_Device), 1, &write, 0, NULL); + + // Create texture for new depth buffer + VkImageCreateInfo dsNewImInfo = { + VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + NULL, + 0, + VK_IMAGE_TYPE_2D, + dsNewFmt, + depthImageInfo.extent, + (uint32_t)depthImageInfo.mipLevels, + (uint32_t)depthImageInfo.arrayLayers, + depthImageInfo.samples, + VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, + VK_SHARING_MODE_EXCLUSIVE, + 0, + NULL, + VK_IMAGE_LAYOUT_UNDEFINED, + }; + + vkr = m_pDriver->vkCreateImage(m_Device, &dsNewImInfo, NULL, &dsImage); + CheckVkResult(vkr); + + NameVulkanObject(dsImage, "Overlay Depth+Stencil Image"); + + VkMemoryRequirements mrq = {0}; + m_pDriver->vkGetImageMemoryRequirements(m_Device, dsImage, &mrq); + + VkMemoryAllocateInfo allocInfo = { + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + NULL, + mrq.size, + m_pDriver->GetGPULocalMemoryIndex(mrq.memoryTypeBits), + }; + + vkr = m_pDriver->vkAllocateMemory(m_Device, &allocInfo, NULL, &dsImageMem); + CheckVkResult(vkr); + + if(vkr != VK_SUCCESS) + return ResourceId(); + + vkr = m_pDriver->vkBindImageMemory(m_Device, dsImage, dsImageMem, 0); + CheckVkResult(vkr); + + cmd = m_pDriver->GetNextCmd(); + if(cmd == VK_NULL_HANDLE) + return ResourceId(); + + vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo); + CheckVkResult(vkr); + + // move original depth buffer to shader read state + m_pDriver->FindImageState(depthIm)->InlineTransition( + cmd, m_pDriver->m_QueueFamilyIdx, VK_IMAGE_LAYOUT_GENERAL, + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, + m_pDriver->GetImageTransitionInfo()); + + // transition new depth buffer to depth write state + m_pDriver->FindImageState(GetResID(dsImage)) + ->InlineTransition(cmd, m_pDriver->m_QueueFamilyIdx, VK_IMAGE_LAYOUT_GENERAL, 0, + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + m_pDriver->GetImageTransitionInfo()); + + vkr = vt->EndCommandBuffer(Unwrap(cmd)); + CheckVkResult(vkr); + cmd = VK_NULL_HANDLE; + + dsSubRange = { + VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, + sub.mip, + 1, + sub.slice, + sub.numSlices, + }; + + dsViewInfo = { + VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + NULL, + 0, + dsImage, + VK_IMAGE_VIEW_TYPE_2D, + dsNewFmt, + {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY}, + dsSubRange, + }; + + vkr = m_pDriver->vkCreateImageView(m_Device, &dsViewInfo, NULL, &dsView); + CheckVkResult(vkr); + } + VkImageView views[] = { m_Overlay.ImageView, - m_pDriver->GetResourceManager()->GetCurrentHandle(depthStencilView), + dsView, }; // Create framebuffer rendering just to overlay image, no depth @@ -1708,6 +1890,50 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, D vkr = m_pDriver->vkCreateFramebuffer(m_Device, &fbinfo, NULL, &depthFB); CheckVkResult(vkr); + + // Fullscreen pass using shader to copy original depth buffer -> new depth buffer + // Pipeline also writes 0 to the stencil during the pass + if(needDepthCopyToDepthStencil) + { + cmd = m_pDriver->GetNextCmd(); + if(cmd == VK_NULL_HANDLE) + return ResourceId(); + + vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo); + CheckVkResult(vkr); + + VkClearValue clearval = {}; + VkRenderPassBeginInfo rpbegin = { + VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + NULL, + Unwrap(depthRP), + Unwrap(depthFB), + state.renderArea, + 1, + &clearval, + }; + vt->CmdBeginRenderPass(Unwrap(cmd), &rpbegin, VK_SUBPASS_CONTENTS_INLINE); + + vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, + Unwrap(m_Overlay.m_DepthCopyPipeline[fmtIndex][sampleIndex])); + vt->CmdBindDescriptorSets(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, + Unwrap(m_Overlay.m_DepthCopyPipeLayout), 0, 1, + UnwrapPtr(m_Overlay.m_DepthCopyDescSet), 0, NULL); + + VkViewport viewport = { + 0.0f, 0.0f, (float)m_Overlay.ImageDim.width, (float)m_Overlay.ImageDim.height, + 0.0f, 1.0f, + }; + vt->CmdSetViewport(Unwrap(cmd), 0, 1, &viewport); + + vt->CmdDraw(Unwrap(cmd), 4, 1, 0, 0); + vt->CmdEndRenderPass(Unwrap(cmd)); + + vkr = vt->EndCommandBuffer(Unwrap(cmd)); + CheckVkResult(vkr); + cmd = VK_NULL_HANDLE; + } + dsFmt = dsNewFmt; } // if depthRP is NULL, so is depthFB, and it means no depth buffer was @@ -1722,7 +1948,7 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, D // make patched shader VkShaderModule failmod = {}, passmod = {}; - VkPipeline failpipe = {}, passpipe = {}; + VkPipeline failpipe = {}, passpipe = {}, depthWriteStencilPipe = {}; // first shader, no depth/stencil testing, writes red GetDebugManager()->PatchFixedColShader(failmod, highlightCol); @@ -1768,6 +1994,7 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, D // subpass 0 in either render pass pipeCreateInfo.subpass = 0; + VkPipelineShaderStageCreateInfo orgFragShader = {}; VkPipelineShaderStageCreateInfo *fragShader = NULL; for(uint32_t i = 0; i < pipeCreateInfo.stageCount; i++) @@ -1776,6 +2003,7 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, D (VkPipelineShaderStageCreateInfo &)pipeCreateInfo.pStages[i]; if(sh.stage == VK_SHADER_STAGE_FRAGMENT_BIT) { + orgFragShader = sh; sh.pName = "main"; fragShader = &sh; break; @@ -1784,6 +2012,7 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, D if(fragShader == NULL) { + useDepthWriteStencilPass = false; // we know this is safe because it's pointing to a static array that's // big enough for all shaders @@ -1832,6 +2061,7 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, D // disable culling/discard and enable depth clamp. That way we show any failures due to these VkPipelineRasterizationStateCreateInfo *rs = (VkPipelineRasterizationStateCreateInfo *)pipeCreateInfo.pRasterizationState; + VkPipelineRasterizationStateCreateInfo orgRS = *rs; rs->cullMode = VK_CULL_MODE_NONE; rs->rasterizerDiscardEnable = false; @@ -1842,6 +2072,39 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, D &failpipe); CheckVkResult(vkr); + if(useDepthWriteStencilPass) + { + pipeCreateInfo.renderPass = depthRP; + *rs = orgRS; + + // disable colour write + for(uint32_t i = 0; i < cb->attachmentCount; i++) + { + VkPipelineColorBlendAttachmentState *att = + (VkPipelineColorBlendAttachmentState *)&cb->pAttachments[i]; + att->blendEnable = false; + att->colorWriteMask = 0x0; + } + + // Write stencil 0x1 for depth passing pixels + ds->stencilTestEnable = true; + ds->front.compareOp = VK_COMPARE_OP_ALWAYS; + ds->front.failOp = VK_STENCIL_OP_KEEP; + ds->front.depthFailOp = VK_STENCIL_OP_KEEP; + ds->front.passOp = VK_STENCIL_OP_REPLACE; + ds->front.compareMask = 0xff; + ds->front.reference = 0x1; + ds->front.writeMask = 0xff; + ds->back = ds->front; + + // Use original shader + *fragShader = orgFragShader; + + vkr = m_pDriver->vkCreateGraphicsPipelines(m_Device, VK_NULL_HANDLE, 1, &pipeCreateInfo, + NULL, &depthWriteStencilPipe); + CheckVkResult(vkr); + } + // modify state state.SetRenderPass(GetResID(m_Overlay.NoDepthRP)); state.subpass = 0; @@ -1858,7 +2121,11 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, D m_pDriver->ReplayLog(0, eventId, eReplay_OnlyDraw); - state.graphics.pipeline = GetResID(passpipe); + if(useDepthWriteStencilPass) + state.graphics.pipeline = GetResID(depthWriteStencilPipe); + else + state.graphics.pipeline = GetResID(passpipe); + if(depthRP != VK_NULL_HANDLE) { state.SetRenderPass(GetResID(depthRP)); @@ -1872,6 +2139,47 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, D m_pDriver->ReplayLog(0, eventId, eReplay_OnlyDraw); + if(useDepthWriteStencilPass) + { + // Resolve stencil = 0x1 pixels to green + cmd = m_pDriver->GetNextCmd(); + + if(cmd == VK_NULL_HANDLE) + return ResourceId(); + + RDCASSERT((dsFmt == VK_FORMAT_D24_UNORM_S8_UINT) || (dsFmt == VK_FORMAT_D32_SFLOAT_S8_UINT)); + vkr = vt->BeginCommandBuffer(Unwrap(cmd), &beginInfo); + CheckVkResult(vkr); + + VkClearValue clearval = {}; + VkRenderPassBeginInfo rpbegin = { + VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + NULL, + Unwrap(depthRP), + Unwrap(depthFB), + state.renderArea, + 1, + &clearval, + }; + vt->CmdBeginRenderPass(Unwrap(cmd), &rpbegin, VK_SUBPASS_CONTENTS_INLINE); + + vt->CmdBindPipeline(Unwrap(cmd), VK_PIPELINE_BIND_POINT_GRAPHICS, + Unwrap(m_Overlay.m_DepthResolvePipeline[fmtIndex][sampleIndex])); + + VkViewport viewport = { + 0.0f, 0.0f, (float)m_Overlay.ImageDim.width, (float)m_Overlay.ImageDim.height, + 0.0f, 1.0f, + }; + vt->CmdSetViewport(Unwrap(cmd), 0, 1, &viewport); + + vt->CmdDraw(Unwrap(cmd), 4, 1, 0, 0); + vt->CmdEndRenderPass(Unwrap(cmd)); + + vkr = vt->EndCommandBuffer(Unwrap(cmd)); + CheckVkResult(vkr); + cmd = VK_NULL_HANDLE; + } + // submit & flush so that we don't have to keep pipeline around for a while m_pDriver->SubmitCmds(); m_pDriver->FlushQ(); @@ -1891,6 +2199,9 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, D m_pDriver->vkDestroyShaderModule(m_Device, failmod, NULL); m_pDriver->vkDestroyPipeline(m_Device, passpipe, NULL); m_pDriver->vkDestroyShaderModule(m_Device, passmod, NULL); + m_pDriver->vkDestroyPipeline(m_Device, depthWriteStencilPipe, NULL); + m_pDriver->vkDestroyImage(m_Device, dsImage, NULL); + m_pDriver->vkFreeMemory(m_Device, dsImageMem, NULL); if(depthRP != VK_NULL_HANDLE) { diff --git a/renderdoc/driver/vulkan/vk_replay.h b/renderdoc/driver/vulkan/vk_replay.h index 2a12a342a..937e56709 100644 --- a/renderdoc/driver/vulkan/vk_replay.h +++ b/renderdoc/driver/vulkan/vk_replay.h @@ -670,10 +670,21 @@ private: VkPipelineLayout m_QuadResolvePipeLayout = VK_NULL_HANDLE; VkPipeline m_QuadResolvePipeline[8] = {VK_NULL_HANDLE}; + VkDescriptorSetLayout m_DepthCopyDescSetLayout = VK_NULL_HANDLE; + VkDescriptorSet m_DepthCopyDescSet = VK_NULL_HANDLE; + VkPipelineLayout m_DepthCopyPipeLayout = VK_NULL_HANDLE; + VkPipeline m_DepthCopyPipeline[2][5]; + + VkPipelineLayout m_DepthResolvePipeLayout = VK_NULL_HANDLE; + VkPipeline m_DepthResolvePipeline[2][5]; + GPUBuffer m_TriSizeUBO; VkDescriptorSetLayout m_TriSizeDescSetLayout = VK_NULL_HANDLE; VkDescriptorSet m_TriSizeDescSet = VK_NULL_HANDLE; VkPipelineLayout m_TriSizePipeLayout = VK_NULL_HANDLE; + + VkSampler m_PointSampler = VK_NULL_HANDLE; + VkFormat m_DefaultDepthStencilFormat; } m_Overlay; struct MeshRendering diff --git a/renderdoc/driver/vulkan/vk_shader_cache.cpp b/renderdoc/driver/vulkan/vk_shader_cache.cpp index 147aa08f5..67dce8f3e 100644 --- a/renderdoc/driver/vulkan/vk_shader_cache.cpp +++ b/renderdoc/driver/vulkan/vk_shader_cache.cpp @@ -131,6 +131,10 @@ static const BuiltinShaderConfig builtinShaders[] = { BuiltinShaderConfig(BuiltinShader::DepthBuf2MSFS, EmbeddedResource(glsl_vk_depthbuf2ms_frag), rdcspv::ShaderStage::Fragment, FeatureCheck::SampleShading | FeatureCheck::NonMetalBackend), + BuiltinShaderConfig(BuiltinShader::DepthCopyFS, EmbeddedResource(glsl_depth_copy_frag), + rdcspv::ShaderStage::Fragment, FeatureCheck::FragmentStores), + BuiltinShaderConfig(BuiltinShader::DepthCopyMSFS, EmbeddedResource(glsl_depth_copyms_frag), + rdcspv::ShaderStage::Fragment, FeatureCheck::FragmentStores), }; RDCCOMPILE_ASSERT(ARRAY_COUNT(builtinShaders) == arraydim(), diff --git a/renderdoc/driver/vulkan/vk_shader_cache.h b/renderdoc/driver/vulkan/vk_shader_cache.h index d15730fd9..b574d07e5 100644 --- a/renderdoc/driver/vulkan/vk_shader_cache.h +++ b/renderdoc/driver/vulkan/vk_shader_cache.h @@ -60,6 +60,8 @@ enum class BuiltinShader DepthMS2BufferCS, Buffer2MSCS, DepthBuf2MSFS, + DepthCopyFS, + DepthCopyMSFS, Count, };