Implement depthBoundsTest
The depthBoundsTest checks if the depth is withing a certain range, and
if not, sets coverage to 0 for the particular fragment.
Tests: dEQP-VK.pipeline.depth.nocolor.format.d16_unorm.compare_ops.*
Tests: dEQP-VK.pipeline.depth.nocolor.format.d32_sfloat.compare_ops.*
Tests: dEQP-VK.pipeline.depth.nocolor.format.d32_sfloat_s8_uint.compare_ops.*
Tests: dEQP-VK.pipeline.depth.nocolor.format.d32_sfloat_s8_uint_separate_layouts.compare_ops.*
Tests: dEQP-VK.dynamic_state.ds_state.depth_bounds_1
Tests: dEQP-VK.dynamic_state.ds_state.depth_bounds_2
Tests: dEQP-VK.rasterization.frag_side_effects.color_at_end.depth_bounds
Tests: dEQP-VK.rasterization.frag_side_effects.color_at_beginning.depth_bounds
Bug: b/181656417
Change-Id: I50076834afa21f5b93e59b27a5438ba26f8008c8
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/53888
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Tested-by: Sean Risser <srisser@google.com>
Commit-Queue: Sean Risser <srisser@google.com>
diff --git a/src/Device/Context.cpp b/src/Device/Context.cpp
index df37f02..cfb8567 100644
--- a/src/Device/Context.cpp
+++ b/src/Device/Context.cpp
@@ -457,12 +457,10 @@
UNSUPPORTED("pCreateInfo->pDepthStencilState->flags %d", int(pCreateInfo->pDepthStencilState->flags));
}
- if(depthStencilState->depthBoundsTestEnable != VK_FALSE)
- {
- UNSUPPORTED("VkPhysicalDeviceFeatures::depthBounds");
- }
-
depthBoundsTestEnable = (depthStencilState->depthBoundsTestEnable != VK_FALSE);
+ minDepthBounds = depthStencilState->minDepthBounds;
+ maxDepthBounds = depthStencilState->maxDepthBounds;
+
depthBufferEnable = (depthStencilState->depthTestEnable != VK_FALSE);
depthWriteEnable = (depthStencilState->depthWriteEnable != VK_FALSE);
depthCompareMode = depthStencilState->depthCompareOp;
@@ -593,6 +591,11 @@
return attachments.stencilBuffer && stencilEnable;
}
+bool GraphicsState::depthBoundsTestActive() const
+{
+ return depthBoundsTestEnable;
+}
+
const GraphicsState GraphicsState::combineStates(const DynamicState &dynamicState) const
{
GraphicsState combinedState = *this;
@@ -627,7 +630,8 @@
ASSERT(dynamicState.minDepthBounds >= 0.0f && dynamicState.minDepthBounds <= 1.0f);
ASSERT(dynamicState.maxDepthBounds >= 0.0f && dynamicState.maxDepthBounds <= 1.0f);
- UNSUPPORTED("VkPhysicalDeviceFeatures::depthBounds");
+ combinedState.minDepthBounds = dynamicState.minDepthBounds;
+ combinedState.maxDepthBounds = dynamicState.maxDepthBounds;
}
if(hasDynamicState(VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK) && stencilEnable)
diff --git a/src/Device/Context.hpp b/src/Device/Context.hpp
index ba2b493..2e15d47 100644
--- a/src/Device/Context.hpp
+++ b/src/Device/Context.hpp
@@ -155,6 +155,8 @@
inline float getConstantDepthBias() const { return constantDepthBias; }
inline float getSlopeDepthBias() const { return slopeDepthBias; }
inline float getDepthBiasClamp() const { return depthBiasClamp; }
+ inline float getMinDepthBounds() const { return minDepthBounds; }
+ inline float getMaxDepthBounds() const { return maxDepthBounds; }
inline bool hasDepthRangeUnrestricted() const { return depthRangeUnrestricted; }
// Pixel processor states
@@ -184,6 +186,7 @@
bool depthWriteActive(const Attachments &attachments) const;
bool depthBufferActive(const Attachments &attachments) const;
bool stencilActive(const Attachments &attachments) const;
+ bool depthBoundsTestActive() const;
private:
inline bool hasDynamicState(VkDynamicState dynamicState) const { return (dynamicStateFlags & (1 << dynamicState)) != 0; }
@@ -219,6 +222,8 @@
float constantDepthBias;
float slopeDepthBias;
float depthBiasClamp;
+ float minDepthBounds;
+ float maxDepthBounds;
bool depthRangeUnrestricted;
// Pixel processor states
diff --git a/src/Device/PixelProcessor.cpp b/src/Device/PixelProcessor.cpp
index 16afb8a..fa85953 100644
--- a/src/Device/PixelProcessor.cpp
+++ b/src/Device/PixelProcessor.cpp
@@ -123,6 +123,10 @@
state.depthClamp = !state.depthFormat.isFloatFormat() || !pipelineState.hasDepthRangeUnrestricted();
}
+ state.depthBoundsTestActive = pipelineState.depthBoundsTestActive();
+ state.minDepthBounds = pipelineState.getMinDepthBounds();
+ state.maxDepthBounds = pipelineState.getMaxDepthBounds();
+
state.occlusionEnabled = occlusionEnabled;
bool fragmentContainsKill = (fragmentShader && fragmentShader->getModes().ContainsKill);
diff --git a/src/Device/PixelProcessor.hpp b/src/Device/PixelProcessor.hpp
index b2ae47c..b7187d4 100644
--- a/src/Device/PixelProcessor.hpp
+++ b/src/Device/PixelProcessor.hpp
@@ -77,6 +77,7 @@
StencilOpState backStencil;
bool depthTestActive;
+ bool depthBoundsTestActive;
bool occlusionEnabled;
bool perspective;
@@ -91,6 +92,8 @@
bool centroid;
bool sampleShadingEnabled;
float minSampleShading;
+ float minDepthBounds;
+ float maxDepthBounds;
VkFrontFace frontFace;
vk::Format depthFormat;
bool depthBias;
diff --git a/src/Device/QuadRasterizer.cpp b/src/Device/QuadRasterizer.cpp
index 024be64..c56d4da 100644
--- a/src/Device/QuadRasterizer.cpp
+++ b/src/Device/QuadRasterizer.cpp
@@ -83,7 +83,7 @@
}
}
- if(state.depthTestActive)
+ if(state.depthTestActive || state.depthBoundsTestActive)
{
zBuffer = *Pointer<Pointer<Byte>>(data + OFFSET(DrawData, depthBuffer)) + yMin * *Pointer<Int>(data + OFFSET(DrawData, depthPitchB));
}
@@ -216,7 +216,7 @@
}
}
- if(state.depthTestActive)
+ if(state.depthTestActive || state.depthBoundsTestActive)
{
zBuffer += *Pointer<Int>(data + OFFSET(DrawData, depthPitchB)) << (1 + clusterCountLog2); // FIXME: Precompute
}
diff --git a/src/Pipeline/PixelRoutine.cpp b/src/Pipeline/PixelRoutine.cpp
index 7272825..f94155e 100644
--- a/src/Pipeline/PixelRoutine.cpp
+++ b/src/Pipeline/PixelRoutine.cpp
@@ -141,6 +141,7 @@
for(unsigned int q = sampleLoopInit; q < sampleLoopEnd; q++)
{
depthPass = depthPass || depthTest(zBuffer, q, x, z[q], sMask[q], zMask[q], cMask[q]);
+ depthBoundsTest(zBuffer, q, x, zMask[q], cMask[q]);
}
}
@@ -307,6 +308,7 @@
for(unsigned int q = sampleLoopInit; q < sampleLoopEnd; q++)
{
depthPass = depthPass || depthTest(zBuffer, q, x, z[q], sMask[q], zMask[q], cMask[q]);
+ depthBoundsTest(zBuffer, q, x, zMask[q], cMask[q]);
}
}
@@ -604,6 +606,58 @@
}
}
+Int4 PixelRoutine::depthBoundsTest16(const Pointer<Byte> &zBuffer, int q, const Int &x)
+{
+ Pointer<Byte> buffer = zBuffer + 2 * x;
+ Int pitch = *Pointer<Int>(data + OFFSET(DrawData, depthPitchB));
+
+ if(q > 0)
+ {
+ buffer += q * *Pointer<Int>(data + OFFSET(DrawData, depthSliceB));
+ }
+
+ Float4 minDepthBound(state.minDepthBounds);
+ Float4 maxDepthBound(state.maxDepthBounds);
+
+ Int2 z;
+ z = Insert(z, *Pointer<Int>(buffer), 0);
+ z = Insert(z, *Pointer<Int>(buffer + pitch), 1);
+
+ Float4 zValue = convertFloat32(As<UShort4>(z));
+ return Int4(CmpLE(minDepthBound, zValue) & CmpLE(zValue, maxDepthBound));
+}
+
+Int4 PixelRoutine::depthBoundsTest32F(const Pointer<Byte> &zBuffer, int q, const Int &x)
+{
+ Pointer<Byte> buffer = zBuffer + 4 * x;
+ Int pitch = *Pointer<Int>(data + OFFSET(DrawData, depthPitchB));
+
+ if(q > 0)
+ {
+ buffer += q * *Pointer<Int>(data + OFFSET(DrawData, depthSliceB));
+ }
+
+ Float4 zValue = Float4(*Pointer<Float2>(buffer), *Pointer<Float2>(buffer + pitch));
+ return Int4(CmpLE(Float4(state.minDepthBounds), zValue) & CmpLE(zValue, Float4(state.maxDepthBounds)));
+}
+
+void PixelRoutine::depthBoundsTest(const Pointer<Byte> &zBuffer, int q, const Int &x, Int &zMask, Int &cMask)
+{
+ if(state.depthBoundsTestActive)
+ {
+ Int4 zTest = (state.depthFormat == VK_FORMAT_D16_UNORM) ? depthBoundsTest16(zBuffer, q, x) : depthBoundsTest32F(zBuffer, q, x);
+
+ if(!state.depthTestActive)
+ {
+ cMask &= zMask & SignMask(zTest);
+ }
+ else
+ {
+ zMask &= cMask & SignMask(zTest);
+ }
+ }
+}
+
void PixelRoutine::alphaToCoverage(Int cMask[4], const Float4 &alpha, int sampleId)
{
static const int a2c[4] = {
@@ -2788,6 +2842,11 @@
return UShort4(cf * Float4(0xFFFF), saturate);
}
+Float4 PixelRoutine::convertFloat32(const UShort4 &cf)
+{
+ return Float4(cf) * Float4(1.0f / 65535.0f);
+}
+
void PixelRoutine::sRGBtoLinear16_12_16(Vector4s &c)
{
Pointer<Byte> LUT = constants + OFFSET(Constants, sRGBtoLinear12_16);
diff --git a/src/Pipeline/PixelRoutine.hpp b/src/Pipeline/PixelRoutine.hpp
index 46e0362..800f708 100644
--- a/src/Pipeline/PixelRoutine.hpp
+++ b/src/Pipeline/PixelRoutine.hpp
@@ -63,6 +63,7 @@
bool isSRGB(int index) const;
UShort4 convertFixed16(const Float4 &cf, bool saturate = true);
+ Float4 convertFloat32(const UShort4 &cf);
void linearToSRGB12_16(Vector4s &c);
private:
@@ -72,6 +73,7 @@
void stencilOperation(Byte8 &newValue, const Byte8 &bufferValue, const PixelProcessor::States::StencilOpState &ops, bool isBack, const Int &zMask, const Int &sMask);
void stencilOperation(Byte8 &output, const Byte8 &bufferValue, VkStencilOp operation, bool isBack);
Bool depthTest(const Pointer<Byte> &zBuffer, int q, const Int &x, const Float4 &z, const Int &sMask, Int &zMask, const Int &cMask);
+ void depthBoundsTest(const Pointer<Byte> &zBuffer, int q, const Int &x, Int &zMask, Int &cMask);
// Raster operations
void blendFactor(Vector4s &blendFactor, const Vector4s ¤t, const Vector4s &pixel, VkBlendFactor blendFactorActive);
@@ -91,6 +93,9 @@
void writeDepth32F(Pointer<Byte> &zBuffer, int q, const Int &x, const Float4 &z, const Int &zMask);
void writeDepth16(Pointer<Byte> &zBuffer, int q, const Int &x, const Float4 &z, const Int &zMask);
+
+ Int4 depthBoundsTest32F(const Pointer<Byte> &zBuffer, int q, const Int &x);
+ Int4 depthBoundsTest16(const Pointer<Byte> &zBuffer, int q, const Int &x);
};
} // namespace sw
diff --git a/src/Renderer/PixelProcessor.hpp b/src/Renderer/PixelProcessor.hpp
index 2fc292a..2c54398 100644
--- a/src/Renderer/PixelProcessor.hpp
+++ b/src/Renderer/PixelProcessor.hpp
@@ -62,6 +62,7 @@
bool stencilWriteMaskedCCW : 1;
bool depthTestActive : 1;
+ bool depthBoundsTestActive : 1;
bool fogActive : 1;
FogMode pixelFogMode : BITS(FOG_LAST);
bool specularAdd : 1;
diff --git a/src/Vulkan/VkPhysicalDevice.cpp b/src/Vulkan/VkPhysicalDevice.cpp
index 7e72f34..dc507f8 100644
--- a/src/Vulkan/VkPhysicalDevice.cpp
+++ b/src/Vulkan/VkPhysicalDevice.cpp
@@ -49,7 +49,7 @@
VK_FALSE, // depthClamp
VK_TRUE, // depthBiasClamp
VK_TRUE, // fillModeNonSolid
- VK_FALSE, // depthBounds
+ VK_TRUE, // depthBounds
VK_FALSE, // wideLines
VK_TRUE, // largePoints
VK_FALSE, // alphaToOne