Add helper for quantised-checking of depth test failures on fragments

This commit is contained in:
baldurk
2025-10-27 11:50:16 +00:00
parent 50976369db
commit 6f98e46da2
5 changed files with 119 additions and 105 deletions
+45
View File
@@ -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);
+4 -19
View File
@@ -2466,35 +2466,20 @@ rdcarray<PixelModification> D3D11Replay::PixelHistory(rdcarray<EventUsage> 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]));
}
}
+14 -29
View File
@@ -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<PixelModification> D3D12Replay::PixelHistory(rdcarray<EventUsage> 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<float, float> depthBounds = tfCb->GetEventDepthBounds(history[h].eventId);
+40 -22
View File
@@ -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<EventUsage> &modEvents,
rdcarray<PixelModification> &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)
+16 -35
View File
@@ -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<PixelModification> VulkanReplay::PixelHistory(rdcarray<EventUsage> 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<float, float> depthBounds = tfCb->GetEventDepthBounds(history[h].eventId);