Handle depth clipping and depth bounds failure separately

* This prevents truly depth-clipped fragments from being wrongly reported as
  other failures like backface culling.
This commit is contained in:
baldurk
2020-07-20 16:07:36 +01:00
parent 6a8e7cbbe5
commit f6babe77fd
6 changed files with 146 additions and 27 deletions
+2
View File
@@ -580,6 +580,8 @@ private:
s += tr("\nBackface culled");
if(mod.depthClipped)
s += tr("\nDepth Clipped");
if(mod.depthBoundsFailed)
s += tr("\nDepth bounds test failed");
if(mod.scissorClipped)
s += tr("\nScissor Clipped");
if(mod.shaderDiscarded)
+11 -5
View File
@@ -1797,9 +1797,10 @@ struct PixelModification
unboundPS == o.unboundPS && fragIndex == o.fragIndex && primitiveID == o.primitiveID &&
preMod == o.preMod && shaderOut == o.shaderOut && postMod == o.postMod &&
sampleMasked == o.sampleMasked && backfaceCulled == o.backfaceCulled &&
depthClipped == o.depthClipped && viewClipped == o.viewClipped &&
scissorClipped == o.scissorClipped && shaderDiscarded == o.shaderDiscarded &&
depthTestFailed == o.depthTestFailed && stencilTestFailed == o.stencilTestFailed;
depthClipped == o.depthClipped && depthBoundsFailed == o.depthBoundsFailed &&
viewClipped == o.viewClipped && scissorClipped == o.scissorClipped &&
shaderDiscarded == o.shaderDiscarded && depthTestFailed == o.depthTestFailed &&
stencilTestFailed == o.stencilTestFailed;
}
bool operator<(const PixelModification &o) const
{
@@ -1825,6 +1826,8 @@ struct PixelModification
return backfaceCulled < o.backfaceCulled;
if(!(depthClipped == o.depthClipped))
return depthClipped < o.depthClipped;
if(!(depthBoundsFailed == o.depthBoundsFailed))
return depthBoundsFailed < o.depthBoundsFailed;
if(!(viewClipped == o.viewClipped))
return viewClipped < o.viewClipped;
if(!(scissorClipped == o.scissorClipped))
@@ -1871,6 +1874,8 @@ pixel.
bool backfaceCulled;
DOCUMENT("``True`` if depth near/far clipping eliminated this fragment.");
bool depthClipped;
DOCUMENT("``True`` if depth bounds clipping eliminated this fragment.");
bool depthBoundsFailed;
DOCUMENT("``True`` if viewport clipping eliminated this fragment.");
bool viewClipped;
DOCUMENT("``True`` if scissor clipping eliminated this fragment.");
@@ -1891,8 +1896,9 @@ pixel.
)");
bool Passed() const
{
return !sampleMasked && !backfaceCulled && !depthClipped && !viewClipped && !scissorClipped &&
!shaderDiscarded && !depthTestFailed && !stencilTestFailed && !predicationSkipped;
return !sampleMasked && !backfaceCulled && !depthClipped && !depthBoundsFailed &&
!viewClipped && !scissorClipped && !shaderDiscarded && !depthTestFailed &&
!stencilTestFailed && !predicationSkipped;
}
};
+48 -21
View File
@@ -117,22 +117,23 @@ bool isDirectWrite(ResourceUsage usage)
enum : uint32_t
{
TestEnabled_Culling = 1 << 0,
TestEnabled_Scissor = 1 << 1,
TestEnabled_SampleMask = 1 << 2,
TestEnabled_DepthBounds = 1 << 3,
TestEnabled_StencilTesting = 1 << 4,
TestEnabled_DepthTesting = 1 << 5,
TestEnabled_FragmentDiscard = 1 << 6,
TestEnabled_DepthClipping = 1 << 0,
TestEnabled_Culling = 1 << 1,
TestEnabled_Scissor = 1 << 2,
TestEnabled_SampleMask = 1 << 3,
TestEnabled_DepthBounds = 1 << 4,
TestEnabled_StencilTesting = 1 << 5,
TestEnabled_DepthTesting = 1 << 6,
TestEnabled_FragmentDiscard = 1 << 7,
Blending_Enabled = 1 << 7,
UnboundFragmentShader = 1 << 8,
TestMustFail_Culling = 1 << 9,
TestMustFail_Scissor = 1 << 10,
TestMustPass_Scissor = 1 << 11,
TestMustFail_DepthTesting = 1 << 12,
TestMustFail_StencilTesting = 1 << 13,
TestMustFail_SampleMask = 1 << 14,
Blending_Enabled = 1 << 8,
UnboundFragmentShader = 1 << 9,
TestMustFail_Culling = 1 << 10,
TestMustFail_Scissor = 1 << 11,
TestMustPass_Scissor = 1 << 12,
TestMustFail_DepthTesting = 1 << 13,
TestMustFail_StencilTesting = 1 << 14,
TestMustFail_SampleMask = 1 << 15,
DepthTest_Shift = 29,
DepthTest_Always = 0U << DepthTest_Shift,
@@ -1781,6 +1782,9 @@ private:
// Culling
{
if(p.depthClipEnable && !p.depthClampEnable)
flags |= TestEnabled_DepthClipping;
if(pipestate.cullMode != VK_CULL_MODE_NONE)
flags |= TestEnabled_Culling;
@@ -1912,8 +1916,9 @@ private:
PipelineCreationFlags_DisableDepthTest = 1 << 1,
PipelineCreationFlags_DisableStencilTest = 1 << 2,
PipelineCreationFlags_DisableDepthBoundsTest = 1 << 3,
PipelineCreationFlags_FixedColorShader = 1 << 4,
PipelineCreationFlags_IntersectOriginalScissor = 1 << 5,
PipelineCreationFlags_DisableDepthClipping = 1 << 4,
PipelineCreationFlags_FixedColorShader = 1 << 5,
PipelineCreationFlags_IntersectOriginalScissor = 1 << 6,
};
void ReplayDrawWithTests(VkCommandBuffer cmd, uint32_t eid, uint32_t eventFlags,
@@ -1949,13 +1954,24 @@ private:
if(eventFlags & TestEnabled_Culling)
{
uint32_t pipeFlags =
PipelineCreationFlags_DisableDepthTest | PipelineCreationFlags_DisableDepthBoundsTest |
PipelineCreationFlags_DisableStencilTest | PipelineCreationFlags_FixedColorShader;
PipelineCreationFlags_DisableDepthTest | PipelineCreationFlags_DisableDepthClipping |
PipelineCreationFlags_DisableDepthBoundsTest | PipelineCreationFlags_DisableStencilTest |
PipelineCreationFlags_FixedColorShader;
VkPipeline pipe = CreatePipeline(basePipeline, pipeFlags, replacementShaders, outputIndex);
VkMarkerRegion::Set(StringFormat::Fmt("Test culling on %u", eid), cmd);
ReplayDraw(cmd, pipe, eid, TestEnabled_Culling);
}
if(eventFlags & TestEnabled_DepthClipping)
{
uint32_t pipeFlags =
PipelineCreationFlags_DisableDepthTest | PipelineCreationFlags_DisableDepthBoundsTest |
PipelineCreationFlags_DisableStencilTest | PipelineCreationFlags_FixedColorShader;
VkPipeline pipe = CreatePipeline(basePipeline, pipeFlags, replacementShaders, outputIndex);
VkMarkerRegion::Set(StringFormat::Fmt("Test depth clipping on %u", eid), cmd);
ReplayDraw(cmd, pipe, eid, TestEnabled_DepthClipping);
}
// Scissor
if(eventFlags & TestMustFail_Scissor)
return;
@@ -2081,6 +2097,8 @@ private:
ds->stencilTestEnable = VK_FALSE;
if(pipeCreateFlags & PipelineCreationFlags_DisableDepthBoundsTest)
ds->depthBoundsTestEnable = VK_FALSE;
if(pipeCreateFlags & PipelineCreationFlags_DisableDepthClipping)
rs->depthClampEnable = VK_TRUE;
rdcarray<VkPipelineShaderStageCreateInfo> stages;
stages.resize(ci.stageCount);
@@ -3090,6 +3108,15 @@ void UpdateTestsFailed(const TestsFailedCallback *tfCb, uint32_t eventId, uint32
if(mod.backfaceCulled)
return;
if(eventFlags & TestEnabled_DepthClipping)
{
uint64_t occlData = tfCb->GetOcclusionResult(eventId, TestEnabled_DepthClipping);
mod.depthClipped = (occlData == 0);
}
if(mod.depthClipped)
return;
if((eventFlags & (TestEnabled_Scissor | TestMustPass_Scissor | TestMustFail_Scissor)) ==
TestEnabled_Scissor)
{
@@ -3121,9 +3148,9 @@ void UpdateTestsFailed(const TestsFailedCallback *tfCb, uint32_t eventId, uint32
if(eventFlags & TestEnabled_DepthBounds)
{
uint64_t occlData = tfCb->GetOcclusionResult(eventId, TestEnabled_DepthBounds);
mod.depthClipped = (occlData == 0);
mod.depthBoundsFailed = (occlData == 0);
}
if(mod.depthClipped)
if(mod.depthBoundsFailed)
return;
if((eventFlags & (TestEnabled_StencilTesting | TestMustFail_StencilTesting)) ==
+1
View File
@@ -896,6 +896,7 @@ void DoSerialise(SerialiserType &ser, PixelModification &el)
SERIALISE_MEMBER(sampleMasked);
SERIALISE_MEMBER(backfaceCulled);
SERIALISE_MEMBER(depthClipped);
SERIALISE_MEMBER(depthBoundsFailed);
SERIALISE_MEMBER(viewClipped);
SERIALISE_MEMBER(scissorClipped);
SERIALISE_MEMBER(shaderDiscarded);
+27 -1
View File
@@ -224,6 +224,15 @@ void main()
{Vec3f(0.6f, 0.8f, 0.25f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(1.0f, 0.0f)},
{Vec3f(0.4f, 0.7f, 0.25f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)},
{Vec3f(0.2f, 0.8f, 0.25f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)},
// depth bounds prep
{Vec3f(0.6f, -0.3f, 0.3f), Vec4f(1.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)},
{Vec3f(0.7f, -0.5f, 0.5f), Vec4f(1.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)},
{Vec3f(0.8f, -0.3f, 0.7f), Vec4f(1.0f, 0.0f, 0.0f, 1.0f), Vec2f(1.0f, 0.0f)},
// depth bounds clip
{Vec3f(0.6f, -0.3f, 0.3f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)},
{Vec3f(0.7f, -0.5f, 0.5f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)},
{Vec3f(0.8f, -0.3f, 0.7f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(1.0f, 0.0f)},
};
// negate y if we're using negative viewport height
@@ -370,7 +379,7 @@ void main()
depthPipeInfo.dynamicState.dynamicStates.push_back(VK_DYNAMIC_STATE_DEPTH_BOUNDS);
depthPipeInfo.depthStencilState.depthBoundsTestEnable = VK_TRUE;
depthPipe = createGraphicsPipeline(depthPipeInfo);
setName(dynamicStencilMaskPipe, "depthPipe");
setName(depthPipe, "depthPipe");
}
pipeCreateInfo.depthStencilState.stencilTestEnable = VK_TRUE;
@@ -386,11 +395,21 @@ void main()
pipeCreateInfo.depthStencilState.stencilTestEnable = VK_TRUE;
pipeCreateInfo.depthStencilState.front.compareOp = VK_COMPARE_OP_GREATER;
VkPipeline pipe = createGraphicsPipeline(pipeCreateInfo);
pipeCreateInfo.depthStencilState.stencilTestEnable = VK_FALSE;
pipeCreateInfo.rasterizationState.cullMode = VK_CULL_MODE_FRONT_BIT;
VkPipeline cullFrontPipe = createGraphicsPipeline(pipeCreateInfo);
pipeCreateInfo.rasterizationState.cullMode = VK_CULL_MODE_BACK_BIT;
pipeCreateInfo.depthStencilState.depthBoundsTestEnable = VK_TRUE;
pipeCreateInfo.depthStencilState.minDepthBounds = 0.0f;
pipeCreateInfo.depthStencilState.maxDepthBounds = 1.0f;
VkPipeline depthBoundsPipe1 = createGraphicsPipeline(pipeCreateInfo);
pipeCreateInfo.depthStencilState.minDepthBounds = 0.4f;
pipeCreateInfo.depthStencilState.maxDepthBounds = 0.6f;
VkPipeline depthBoundsPipe2 = createGraphicsPipeline(pipeCreateInfo);
pipeCreateInfo.depthStencilState.depthBoundsTestEnable = VK_FALSE;
renderPassCreateInfo.attachments.pop_back();
renderPassCreateInfo.subpasses[0].pDepthStencilAttachment = NULL;
@@ -533,6 +552,13 @@ void main()
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, cullFrontPipe);
vkCmdDraw(cmd, 3, 1, 0, 0);
setMarker(cmd, "Depth Bounds Prep");
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, depthBoundsPipe1);
vkCmdDraw(cmd, 3, 1, 63, 0);
setMarker(cmd, "Depth Bounds Clip");
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, depthBoundsPipe2);
vkCmdDraw(cmd, 3, 1, 66, 0);
// add a marker so we can easily locate this draw
setMarker(cmd, "Test Begin");
@@ -7,6 +7,8 @@ def passed(x): return x.Passed()
def event_id(x): return x.eventId
def culled(x): return x.backfaceCulled
def depth_test_failed(x): return x.depthTestFailed
def depth_clipped(x): return x.depthClipped
def depth_bounds_failed(x): return x.depthBoundsFailed
def scissor_clipped(x): return x.scissorClipped
def stencil_test_failed(x): return x.stencilTestFailed
def shader_discarded(x): return x.shaderDiscarded
@@ -69,6 +71,8 @@ class VK_Pixel_History(rdtest.TestCase):
dynamic_stencil_ref_eid = self.find_draw("Dynamic Stencil Ref").next.eventId
dynamic_stencil_mask_eid = self.find_draw("Dynamic Stencil Mask").next.eventId
depth_test_eid = self.find_draw("Depth Test").next.eventId
depth_bounds_prep_eid = self.find_draw("Depth Bounds Prep").next.eventId
depth_bounds_clip_eid = self.find_draw("Depth Bounds Clip").next.eventId
# For pixel 190, 149 inside the red triangle
x, y = 190, 149
@@ -118,6 +122,59 @@ class VK_Pixel_History(rdtest.TestCase):
self.check_events(events, modifs, False)
self.check_pixel_value(tex, x, y, value_selector(modifs[-1].postMod.col), sub=sub, cast=rt.typeCast)
x, y = 330, 145
rdtest.log.print("Testing pixel {}, {}".format(x, y))
modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.typeCast)
events = [
[[event_id, begin_renderpass_eid], [passed, True]],
[[event_id, test_eid], [passed, True], [primitive_id, 3], [shader_out_col, (0.0, 0.0, 0.0, 2.75)]],
]
self.check_events(events, modifs, False)
self.check_pixel_value(tex, x, y, value_selector(modifs[-1].postMod.col), sub=sub, cast=rt.typeCast)
x, y = 340, 145
rdtest.log.print("Testing pixel {}, {}".format(x, y))
modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.typeCast)
events = [
[[event_id, begin_renderpass_eid], [passed, True]],
[[event_id, test_eid], [passed, False], [depth_clipped, True]],
]
self.check_events(events, modifs, False)
self.check_pixel_value(tex, x, y, value_selector(modifs[-1].postMod.col), sub=sub, cast=rt.typeCast)
x, y = 330, 105
rdtest.log.print("Testing pixel {}, {}".format(x, y))
modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.typeCast)
events = [
[[event_id, begin_renderpass_eid], [passed, True]],
[[event_id, depth_bounds_prep_eid], [passed, True], [primitive_id, 0], [shader_out_col, (1.0, 0.0, 0.0, 2.75)]],
[[event_id, depth_bounds_clip_eid], [passed, True], [primitive_id, 0], [shader_out_col, (0.0, 1.0, 0.0, 2.75)]],
]
self.check_events(events, modifs, False)
self.check_pixel_value(tex, x, y, value_selector(modifs[-1].postMod.col), sub=sub, cast=rt.typeCast)
x, y = 320, 105
rdtest.log.print("Testing pixel {}, {}".format(x, y))
modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.typeCast)
events = [
[[event_id, begin_renderpass_eid], [passed, True]],
[[event_id, depth_bounds_prep_eid], [passed, True], [primitive_id, 0], [shader_out_col, (1.0, 0.0, 0.0, 2.75)]],
[[event_id, depth_bounds_clip_eid], [passed, False], [depth_bounds_failed, True]],
]
self.check_events(events, modifs, False)
self.check_pixel_value(tex, x, y, value_selector(modifs[-1].postMod.col), sub=sub, cast=rt.typeCast)
x, y = 345, 105
rdtest.log.print("Testing pixel {}, {}".format(x, y))
modifs: List[rd.PixelModification] = self.controller.PixelHistory(tex, x, y, sub, rt.typeCast)
events = [
[[event_id, begin_renderpass_eid], [passed, True]],
[[event_id, depth_bounds_prep_eid], [passed, True], [primitive_id, 0], [shader_out_col, (1.0, 0.0, 0.0, 2.75)]],
[[event_id, depth_bounds_clip_eid], [passed, False], [depth_bounds_failed, True]],
]
self.check_events(events, modifs, False)
self.check_pixel_value(tex, x, y, value_selector(modifs[-1].postMod.col), sub=sub, cast=rt.typeCast)
rdtest.log.print("Testing dynamic state pipelines")
self.controller.SetFrameEvent(dynamic_stencil_mask_eid, True)