diff --git a/renderdoc/driver/vulkan/vk_debug.cpp b/renderdoc/driver/vulkan/vk_debug.cpp index 51ebfc130d..0fc2dbaadc 100644 --- a/renderdoc/driver/vulkan/vk_debug.cpp +++ b/renderdoc/driver/vulkan/vk_debug.cpp @@ -225,7 +225,8 @@ struct ConciseGraphicsPipeline }; static void create(WrappedVulkan *driver, const char *objName, const int line, VkPipeline *pipe, - const ConciseGraphicsPipeline &info) + const ConciseGraphicsPipeline &info, + const VkPipelineDepthStencilStateCreateInfo &depthStencil) { // if the module didn't compile, this pipeline is not be supported. Silently don't create it, code // later should handle the missing pipeline as indicating lack of support @@ -260,21 +261,6 @@ static void create(WrappedVulkan *driver, const char *objName, const int line, V msaa.sampleShadingEnable = true; } - const VkPipelineDepthStencilStateCreateInfo depthStencil = { - VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, - NULL, - 0, - info.depthEnable, - info.depthEnable, - 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}, - 0.0f, - 1.0f, - }; - const VkPipelineColorBlendAttachmentState colAttach = { info.blendEnable, // colour blending @@ -360,6 +346,27 @@ static void create(WrappedVulkan *driver, const char *objName, const int line, V RDCERR("Failed creating object %s at line %i, vkr was %s", objName, line, ToStr(vkr).c_str()); } +static void create(WrappedVulkan *driver, const char *objName, const int line, VkPipeline *pipe, + const ConciseGraphicsPipeline &info) +{ + const VkPipelineDepthStencilStateCreateInfo depthStencil = { + VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, + NULL, + 0, + info.depthEnable, + info.depthEnable, + 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}, + 0.0f, + 1.0f, + }; + + create(driver, objName, line, pipe, info, depthStencil); +} + // utility macro that lets us check for VkResult failures inside the utility helpers while // preserving context from outside #define CREATE_OBJECT(obj, ...) create(driver, #obj, __LINE__, &obj, __VA_ARGS__) @@ -3825,6 +3832,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}}); @@ -3839,12 +3848,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"); @@ -3899,7 +3920,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); @@ -3924,9 +3945,291 @@ 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 + VK_STENCIL_OP_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 + VK_STENCIL_OP_KEEP, + true, // colourOutput + false, // blendEnable + VK_BLEND_FACTOR_DST_ALPHA, + VK_BLEND_FACTOR_ONE, + 0xf, // writeMask + }; + + const VkPipelineDepthStencilStateCreateInfo depthStencil = { + VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, + NULL, + 0, + false, + false, + VK_COMPARE_OP_ALWAYS, + false, + true, + { + VK_STENCIL_OP_KEEP, + VK_STENCIL_OP_KEEP, + VK_STENCIL_OP_KEEP, + VK_COMPARE_OP_EQUAL, + 0xff, + 0x0, + 1, + }, + { + VK_STENCIL_OP_KEEP, + VK_STENCIL_OP_KEEP, + VK_STENCIL_OP_KEEP, + VK_COMPARE_OP_EQUAL, + 0xff, + 0x0, + 1, + }, + 0.0f, + 1.0f, + }; + + 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, depthStencil); + + 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); @@ -3959,6 +4262,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++) @@ -3971,6 +4287,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 bb16fc0f09..7c17497021 100644 --- a/renderdoc/driver/vulkan/vk_overlay.cpp +++ b/renderdoc/driver/vulkan/vk_overlay.cpp @@ -1189,13 +1189,14 @@ ResourceId VulkanReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, D RemoveNextStruct(&pipeCreateInfo, VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO); VkPipelineShaderStageCreateInfo *fragShader = NULL; - + VkPipelineShaderStageCreateInfo originalSH; for(uint32_t i = 0; i < pipeCreateInfo.stageCount; i++) { VkPipelineShaderStageCreateInfo &sh = (VkPipelineShaderStageCreateInfo &)pipeCreateInfo.pStages[i]; if(sh.stage == VK_SHADER_STAGE_FRAGMENT_BIT) { + originalSH = sh; sh.module = mod[0]; sh.pName = "main"; fragShader = &sh; @@ -1567,6 +1568,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 +1599,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 +1607,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 +1630,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 +1657,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 +1737,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 +1892,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 +1950,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 +1996,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 +2005,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 +2014,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 +2063,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 +2074,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 +2123,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 +2141,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 +2201,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 c5af74e056..a8b0e732fc 100644 --- a/renderdoc/driver/vulkan/vk_replay.h +++ b/renderdoc/driver/vulkan/vk_replay.h @@ -646,10 +646,21 @@ class VulkanReplay : public IReplayDriver 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 4735031419..1884d7b186 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 d15730fd97..b574d07e5e 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, };