diff --git a/renderdoc/api/replay/data_types.h b/renderdoc/api/replay/data_types.h index 5a6f6ac44..fa487696c 100644 --- a/renderdoc/api/replay/data_types.h +++ b/renderdoc/api/replay/data_types.h @@ -2736,6 +2736,51 @@ pixel. !viewClipped && !scissorClipped && !shaderDiscarded && !depthTestFailed && !stencilTestFailed && !predicationSkipped; } + + DOCUMENT(R"(Update the depth-test failure state based on known shader output depth value and +preMod reference value, quantised to a certain number of depth bits with epsilon. + +This is primarily used internally and should not be needed to be called externally. + +:param int depthBits: How many bits are in the depth buffer: 16, 24 or 32. +:param CompareFunction depthFunc: The comparison function active for the depth test +)"); + void CheckDepthTestQuantised(uint32_t depthBits, CompareFunction depthFunc) + { + float shadDepth = shaderOut.depth; + const float compareDepth = preMod.depth; + + float eps = 1.2e-7f; + if(depthBits == 24) + { + shadDepth = float(uint32_t(float(shadDepth * 0xffffff))) / float(0xffffff); + eps = float(1.0f) / float(0xffffff); + } + else if(depthBits == 16) + { + shadDepth = float(uint32_t(float(shadDepth * 0xffff))) / float(0xffff); + eps = float(1.0f) / float(0xffff); + } + + bool passed = true; + if(depthFunc == CompareFunction::Equal) + passed = shadDepth > compareDepth ? ((shadDepth - compareDepth) <= eps) + : ((compareDepth - shadDepth) <= eps); + else if(depthFunc == CompareFunction::NotEqual) + passed = shadDepth > compareDepth ? ((shadDepth - compareDepth) > eps) + : ((compareDepth - shadDepth) > eps); + else if(depthFunc == CompareFunction::Less) + passed = (shadDepth - eps < compareDepth); + else if(depthFunc == CompareFunction::LessEqual) + passed = (shadDepth - eps <= compareDepth); + else if(depthFunc == CompareFunction::Greater) + passed = (shadDepth + eps > compareDepth); + else if(depthFunc == CompareFunction::GreaterEqual) + passed = (shadDepth + eps >= compareDepth); + + if(!passed) + depthTestFailed = true; + } }; DECLARE_REFLECTION_STRUCT(PixelModification); diff --git a/renderdoc/driver/d3d11/d3d11_pixelhistory.cpp b/renderdoc/driver/d3d11/d3d11_pixelhistory.cpp index 7e04b49a1..32ce4dc07 100644 --- a/renderdoc/driver/d3d11/d3d11_pixelhistory.cpp +++ b/renderdoc/driver/d3d11/d3d11_pixelhistory.cpp @@ -2466,35 +2466,20 @@ rdcarray D3D11Replay::PixelHistory(rdcarray event if(history[h].preMod.depth >= 0.0f && history[h].shaderOut.depth >= 0.0f) { DXGI_FORMAT dfmt = depthFormats[history[h].eventId]; - float shadDepth = history[h].shaderOut.depth; - // quantise depth to match before comparing + uint32_t depthBits = 32; if(dfmt == DXGI_FORMAT_D24_UNORM_S8_UINT || dfmt == DXGI_FORMAT_X24_TYPELESS_G8_UINT || dfmt == DXGI_FORMAT_R24_UNORM_X8_TYPELESS || dfmt == DXGI_FORMAT_R24G8_TYPELESS) { - shadDepth = float(uint32_t(float(shadDepth * 0xffffff))) / float(0xffffff); + depthBits = 24; } else if(dfmt == DXGI_FORMAT_D16_UNORM || dfmt == DXGI_FORMAT_R16_TYPELESS || dfmt == DXGI_FORMAT_R16_UNORM) { - shadDepth = float(uint32_t(float(shadDepth * 0xffff))) / float(0xffff); + depthBits = 16; } - bool passed = true; - if(depthOps[history[h].eventId] == D3D11_COMPARISON_EQUAL) - passed = (shadDepth == history[h].preMod.depth); - else if(depthOps[history[h].eventId] == D3D11_COMPARISON_NOT_EQUAL) - passed = (shadDepth != history[h].preMod.depth); - else if(depthOps[history[h].eventId] == D3D11_COMPARISON_LESS) - passed = (shadDepth < history[h].preMod.depth); - else if(depthOps[history[h].eventId] == D3D11_COMPARISON_LESS_EQUAL) - passed = (shadDepth <= history[h].preMod.depth); - else if(depthOps[history[h].eventId] == D3D11_COMPARISON_GREATER) - passed = (shadDepth > history[h].preMod.depth); - else if(depthOps[history[h].eventId] == D3D11_COMPARISON_GREATER_EQUAL) - passed = (shadDepth >= history[h].preMod.depth); - - history[h].depthTestFailed = !passed; + history[h].CheckDepthTestQuantised(depthBits, MakeCompareFunc(depthOps[history[h].eventId])); } } diff --git a/renderdoc/driver/d3d12/d3d12_pixelhistory.cpp b/renderdoc/driver/d3d12/d3d12_pixelhistory.cpp index ccaae7f41..632f35246 100644 --- a/renderdoc/driver/d3d12/d3d12_pixelhistory.cpp +++ b/renderdoc/driver/d3d12/d3d12_pixelhistory.cpp @@ -212,14 +212,15 @@ enum D3D12PixelHistoryTests : uint32_t TestMustFail_SampleMask = 1 << 15, DepthTest_Shift = 29, - DepthTest_Always = 0U << DepthTest_Shift, - DepthTest_Never = 1U << DepthTest_Shift, - DepthTest_Equal = 2U << DepthTest_Shift, - DepthTest_NotEqual = 3U << DepthTest_Shift, - DepthTest_Less = 4U << DepthTest_Shift, - DepthTest_LessEqual = 5U << DepthTest_Shift, - DepthTest_Greater = 6U << DepthTest_Shift, - DepthTest_GreaterEqual = 7U << DepthTest_Shift, + DepthTest_Mask = 0x7U << DepthTest_Shift, + DepthTest_Always = uint32_t(CompareFunction::AlwaysTrue) << DepthTest_Shift, + DepthTest_Never = uint32_t(CompareFunction::Never) << DepthTest_Shift, + DepthTest_Equal = uint32_t(CompareFunction::Equal) << DepthTest_Shift, + DepthTest_NotEqual = uint32_t(CompareFunction::NotEqual) << DepthTest_Shift, + DepthTest_Less = uint32_t(CompareFunction::Less) << DepthTest_Shift, + DepthTest_LessEqual = uint32_t(CompareFunction::LessEqual) << DepthTest_Shift, + DepthTest_Greater = uint32_t(CompareFunction::Greater) << DepthTest_Shift, + DepthTest_GreaterEqual = uint32_t(CompareFunction::GreaterEqual) << DepthTest_Shift, }; static bool IsDepthFormat(D3D12_RESOURCE_DESC desc) @@ -3291,39 +3292,23 @@ rdcarray D3D12Replay::PixelHistory(rdcarray event { uint32_t flags = tfCb->GetEventFlags(history[h].eventId); - flags &= 0x7 << DepthTest_Shift; - DXGI_FORMAT dfmt = cb.GetDepthFormat(eid); - float shadDepth = history[h].shaderOut.depth; + uint32_t depthBits = 32; // Quantize depth to match before comparing if(dfmt == DXGI_FORMAT_D24_UNORM_S8_UINT || dfmt == DXGI_FORMAT_X24_TYPELESS_G8_UINT || dfmt == DXGI_FORMAT_R24_UNORM_X8_TYPELESS || dfmt == DXGI_FORMAT_R24G8_TYPELESS) { - shadDepth = float(uint32_t(float(shadDepth * 0xffffff))) / float(0xffffff); + depthBits = 24; } else if(dfmt == DXGI_FORMAT_D16_UNORM || dfmt == DXGI_FORMAT_R16_TYPELESS || dfmt == DXGI_FORMAT_R16_UNORM) { - shadDepth = float(uint32_t(float(shadDepth * 0xffff))) / float(0xffff); + depthBits = 16; } - bool passed = true; - if(flags == DepthTest_Equal) - passed = (shadDepth == history[h].preMod.depth); - else if(flags == DepthTest_NotEqual) - passed = (shadDepth != history[h].preMod.depth); - else if(flags == DepthTest_Less) - passed = (shadDepth < history[h].preMod.depth); - else if(flags == DepthTest_LessEqual) - passed = (shadDepth <= history[h].preMod.depth); - else if(flags == DepthTest_Greater) - passed = (shadDepth > history[h].preMod.depth); - else if(flags == DepthTest_GreaterEqual) - passed = (shadDepth >= history[h].preMod.depth); - - if(!passed) - history[h].depthTestFailed = true; + history[h].CheckDepthTestQuantised( + depthBits, CompareFunction((flags & DepthTest_Mask) >> DepthTest_Shift)); rdcpair depthBounds = tfCb->GetEventDepthBounds(history[h].eventId); diff --git a/renderdoc/driver/gl/gl_pixelhistory.cpp b/renderdoc/driver/gl/gl_pixelhistory.cpp index 7a59239d9..791a21949 100644 --- a/renderdoc/driver/gl/gl_pixelhistory.cpp +++ b/renderdoc/driver/gl/gl_pixelhistory.cpp @@ -2011,24 +2011,6 @@ void QueryPrimitiveIdPerFragment(WrappedOpenGL *driver, GLReplay *replay, } } -bool depthTestPassed(int depthFunc, float shaderOutputDepth, float depthInBuffer) -{ - switch(depthFunc) - { - case eGL_NEVER: return false; - case eGL_LESS: return shaderOutputDepth < depthInBuffer; - case eGL_EQUAL: return shaderOutputDepth == depthInBuffer; - case eGL_LEQUAL: return shaderOutputDepth <= depthInBuffer; - case eGL_GREATER: return shaderOutputDepth > depthInBuffer; - case eGL_NOTEQUAL: return shaderOutputDepth != depthInBuffer; - case eGL_GEQUAL: return shaderOutputDepth >= depthInBuffer; - case eGL_ALWAYS: return true; - - default: RDCERR("Unexpected depth function: %d", depthFunc); - } - return false; -} - void CalculateFragmentDepthTests(WrappedOpenGL *driver, GLPixelHistoryResources &resources, const rdcarray &modEvents, rdcarray &history, @@ -2060,9 +2042,9 @@ void CalculateFragmentDepthTests(WrappedOpenGL *driver, GLPixelHistoryResources GLboolean depthTestEnabled = driver->glIsEnabled(eGL_DEPTH_TEST); // default for no depth test - int depthFunc = eGL_ALWAYS; + GLenum depthFunc = eGL_ALWAYS; if(depthTestEnabled) - driver->glGetIntegerv(eGL_DEPTH_FUNC, &depthFunc); + driver->glGetIntegerv(eGL_DEPTH_FUNC, (int *)&depthFunc); for(; historyIndex < history.size() && modEvents[i].eventId == history[historyIndex].eventId; ++historyIndex) { @@ -2071,8 +2053,44 @@ void CalculateFragmentDepthTests(WrappedOpenGL *driver, GLPixelHistoryResources continue; } - history[historyIndex].depthTestFailed = !depthTestPassed( - depthFunc, history[historyIndex].shaderOut.depth, history[historyIndex].preMod.depth); + GLuint curDepth = 0; + GLint depthType = 0; + driver->glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, eGL_DEPTH_ATTACHMENT, + eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, + (GLint *)&curDepth); + + driver->glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, eGL_DEPTH_ATTACHMENT, + eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, + &depthType); + + GLenum depthFormat = eGL_NONE; + + if(curDepth != 0) + { + ResourceId id; + if(depthType != eGL_RENDERBUFFER) + { + id = driver->GetResourceManager()->GetResID(TextureRes(driver->GetCtx(), curDepth)); + } + else + { + id = driver->GetResourceManager()->GetResID(RenderbufferRes(driver->GetCtx(), curDepth)); + } + depthFormat = driver->m_Textures[id].internalFormat; + + uint32_t depthBits = 32; + if(depthFormat == eGL_DEPTH_COMPONENT24 || depthFormat == eGL_DEPTH24_STENCIL8 || + depthFormat == eGL_UNSIGNED_INT_24_8) + { + depthBits = 24; + } + else if(depthFormat == eGL_DEPTH_COMPONENT16) + { + depthBits = 16; + } + + history[historyIndex].CheckDepthTestQuantised(depthBits, MakeCompareFunc(depthFunc)); + } } if(i < modEvents.size() - 1) diff --git a/renderdoc/driver/vulkan/vk_pixelhistory.cpp b/renderdoc/driver/vulkan/vk_pixelhistory.cpp index e0c085e8e..5abba66fd 100644 --- a/renderdoc/driver/vulkan/vk_pixelhistory.cpp +++ b/renderdoc/driver/vulkan/vk_pixelhistory.cpp @@ -136,14 +136,15 @@ enum : uint32_t TestMustFail_SampleMask = 1 << 15, DepthTest_Shift = 29, - DepthTest_Always = 0U << DepthTest_Shift, - DepthTest_Never = 1U << DepthTest_Shift, - DepthTest_Equal = 2U << DepthTest_Shift, - DepthTest_NotEqual = 3U << DepthTest_Shift, - DepthTest_Less = 4U << DepthTest_Shift, - DepthTest_LessEqual = 5U << DepthTest_Shift, - DepthTest_Greater = 6U << DepthTest_Shift, - DepthTest_GreaterEqual = 7U << DepthTest_Shift, + DepthTest_Mask = 0x7U << DepthTest_Shift, + DepthTest_Always = uint32_t(CompareFunction::AlwaysTrue) << DepthTest_Shift, + DepthTest_Never = uint32_t(CompareFunction::Never) << DepthTest_Shift, + DepthTest_Equal = uint32_t(CompareFunction::Equal) << DepthTest_Shift, + DepthTest_NotEqual = uint32_t(CompareFunction::NotEqual) << DepthTest_Shift, + DepthTest_Less = uint32_t(CompareFunction::Less) << DepthTest_Shift, + DepthTest_LessEqual = uint32_t(CompareFunction::LessEqual) << DepthTest_Shift, + DepthTest_Greater = uint32_t(CompareFunction::Greater) << DepthTest_Shift, + DepthTest_GreaterEqual = uint32_t(CompareFunction::GreaterEqual) << DepthTest_Shift, }; struct VkCopyPixelParams @@ -4890,39 +4891,19 @@ rdcarray VulkanReplay::PixelHistory(rdcarray even if(history[h].preMod.depth >= 0.0f && history[h].shaderOut.depth >= 0.0f && tfCb && tfCb->HasEventFlags(history[h].eventId)) { - uint32_t flags = tfCb->GetEventFlags(history[h].eventId); + const uint32_t flags = tfCb->GetEventFlags(history[h].eventId); - flags &= 0x7 << DepthTest_Shift; - - VkFormat dfmt = cb.GetDepthFormat(eid); - float shadDepth = history[h].shaderOut.depth; + const VkFormat dfmt = cb.GetDepthFormat(eid); + uint32_t depthBits = 32; // quantise depth to match before comparing if(dfmt == VK_FORMAT_D24_UNORM_S8_UINT || dfmt == VK_FORMAT_X8_D24_UNORM_PACK32) - { - shadDepth = float(uint32_t(float(shadDepth * 0xffffff))) / float(0xffffff); - } + depthBits = 24; else if(dfmt == VK_FORMAT_D16_UNORM || dfmt == VK_FORMAT_D16_UNORM_S8_UINT) - { - shadDepth = float(uint32_t(float(shadDepth * 0xffff))) / float(0xffff); - } + depthBits = 16; - bool passed = true; - if(flags == DepthTest_Equal) - passed = (shadDepth == history[h].preMod.depth); - else if(flags == DepthTest_NotEqual) - passed = (shadDepth != history[h].preMod.depth); - else if(flags == DepthTest_Less) - passed = (shadDepth < history[h].preMod.depth); - else if(flags == DepthTest_LessEqual) - passed = (shadDepth <= history[h].preMod.depth); - else if(flags == DepthTest_Greater) - passed = (shadDepth > history[h].preMod.depth); - else if(flags == DepthTest_GreaterEqual) - passed = (shadDepth >= history[h].preMod.depth); - - if(!passed) - history[h].depthTestFailed = true; + history[h].CheckDepthTestQuantised( + depthBits, CompareFunction((flags & DepthTest_Mask) >> DepthTest_Shift)); rdcpair depthBounds = tfCb->GetEventDepthBounds(history[h].eventId);