Implement VK_EXT_depth_clip_enable

Normally the vertex processor will clip geometry that's outside of the
near and far planes. However, when depthClamp is enabled, depth clipping
must be disabled. So this change also enables the extension that allows
users to explicitly control depth clipping.

Bug: b/185814882
Tests: dEQP-VK.clipping.clip_volume.depth_clip.*
Change-Id: Iaab31c17cac382cf55a8c50d8e7e7d4c87b55272
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/53968
Presubmit-Ready: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Commit-Queue: Sean Risser <srisser@google.com>
Tested-by: Sean Risser <srisser@google.com>
diff --git a/src/Device/Clipper.cpp b/src/Device/Clipper.cpp
index f5a75e5..f011507 100644
--- a/src/Device/Clipper.cpp
+++ b/src/Device/Clipper.cpp
@@ -261,14 +261,15 @@
 
 namespace sw {
 
-unsigned int Clipper::ComputeClipFlags(const float4 &v)
+unsigned int Clipper::ComputeClipFlags(const float4 &v, bool depthClipEnable)
 {
+	int depthClipFlags = ((v.z > v.w) ? CLIP_FAR : 0) |
+					     ((v.z < 0) ? CLIP_NEAR : 0);
 	return ((v.x > v.w) ? CLIP_RIGHT : 0) |
 	       ((v.y > v.w) ? CLIP_TOP : 0) |
-	       ((v.z > v.w) ? CLIP_FAR : 0) |
 	       ((v.x < -v.w) ? CLIP_LEFT : 0) |
 	       ((v.y < -v.w) ? CLIP_BOTTOM : 0) |
-	       ((v.z < 0) ? CLIP_NEAR : 0) |
+	       (depthClipEnable ? depthClipFlags : 0) |
 	       Clipper::CLIP_FINITE;  // FIXME: xyz finite
 }
 
diff --git a/src/Device/Clipper.hpp b/src/Device/Clipper.hpp
index c696caf..a35a0b4 100644
--- a/src/Device/Clipper.hpp
+++ b/src/Device/Clipper.hpp
@@ -39,7 +39,7 @@
 		CLIP_FINITE = 1 << 7,  // All position coordinates are finite
 	};
 
-	static unsigned int ComputeClipFlags(const float4 &v);
+	static unsigned int ComputeClipFlags(const float4 &v, bool depthClipEnable);
 	static bool Clip(Polygon &polygon, int clipFlagsOr, const DrawCall &draw);
 };
 
diff --git a/src/Device/Context.cpp b/src/Device/Context.cpp
index 2cf2d19..ad04d5b 100644
--- a/src/Device/Context.cpp
+++ b/src/Device/Context.cpp
@@ -324,6 +324,8 @@
 	slopeDepthBias = (rasterizationState->depthBiasEnable != VK_FALSE) ? rasterizationState->depthBiasSlopeFactor : 0.0f;
 	depthBiasClamp = (rasterizationState->depthBiasEnable != VK_FALSE) ? rasterizationState->depthBiasClamp : 0.0f;
 	depthRangeUnrestricted = device->hasExtension(VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME);
+	depthClampEnable = rasterizationState->depthClampEnable != VK_FALSE;
+	depthClipEnable = !depthClampEnable;
 
 	// From the Vulkan spec for vkCmdSetDepthBias:
 	//    The bias value O for a polygon is:
@@ -361,6 +363,14 @@
 				provokingVertexMode = provokingVertexModeCreateInfo->provokingVertexMode;
 			}
 			break;
+		case VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_DEPTH_CLIP_STATE_CREATE_INFO_EXT:
+			{
+				const auto *depthClipInfo = reinterpret_cast<const VkPipelineRasterizationDepthClipStateCreateInfoEXT *>(extensionCreateInfo);
+				// Reserved for future use.
+				ASSERT(depthClipInfo->flags == 0);
+				depthClipEnable = depthClipInfo->depthClipEnable != VK_FALSE;
+			}
+			break;
 		default:
 			WARN("pCreateInfo->pRasterizationState->pNext sType = %s", vk::Stringify(extensionCreateInfo->sType).c_str());
 			break;
diff --git a/src/Device/Context.hpp b/src/Device/Context.hpp
index 2e15d47..4c30b0e 100644
--- a/src/Device/Context.hpp
+++ b/src/Device/Context.hpp
@@ -158,6 +158,8 @@
 	inline float getMinDepthBounds() const { return minDepthBounds; }
 	inline float getMaxDepthBounds() const { return maxDepthBounds; }
 	inline bool hasDepthRangeUnrestricted() const { return depthRangeUnrestricted; }
+	inline bool getDepthClampEnable() const { return depthClampEnable; }
+	inline bool getDepthClipEnable() const { return depthClipEnable; }
 
 	// Pixel processor states
 	inline bool hasRasterizerDiscard() const { return rasterizerDiscard; }
@@ -232,6 +234,8 @@
 	bool depthBufferEnable;
 	VkCompareOp depthCompareMode;
 	bool depthWriteEnable;
+	bool depthClampEnable;
+	bool depthClipEnable;
 
 	float lineWidth;
 
diff --git a/src/Device/Renderer.cpp b/src/Device/Renderer.cpp
index 554fb22..ca15e11 100644
--- a/src/Device/Renderer.cpp
+++ b/src/Device/Renderer.cpp
@@ -267,6 +267,7 @@
 	draw->lineRasterizationMode = pipelineState.getLineRasterizationMode();
 	draw->descriptorSetObjects = inputs.getDescriptorSetObjects();
 	draw->pipelineLayout = pipelineState.getPipelineLayout();
+	draw->depthClipEnable = pipelineState.getDepthClipEnable();
 
 	draw->vertexRoutine = vertexRoutine;
 	draw->setupRoutine = setupRoutine;
@@ -355,6 +356,7 @@
 		data->constantDepthBias = pipelineState.getConstantDepthBias();
 		data->slopeDepthBias = pipelineState.getSlopeDepthBias();
 		data->depthBiasClamp = pipelineState.getDepthBiasClamp();
+		data->depthClipEnable = pipelineState.getDepthClipEnable();
 
 		const vk::Attachments attachments = pipeline->getAttachments();
 		if(attachments.depthBuffer)
@@ -901,19 +903,19 @@
 
 		P[0].x += -dy0w;
 		P[0].y += +dx0h;
-		C[0] = Clipper::ComputeClipFlags(P[0]);
+		C[0] = Clipper::ComputeClipFlags(P[0], draw.depthClipEnable);
 
 		P[1].x += -dy1w;
 		P[1].y += +dx1h;
-		C[1] = Clipper::ComputeClipFlags(P[1]);
+		C[1] = Clipper::ComputeClipFlags(P[1], draw.depthClipEnable);
 
 		P[2].x += +dy1w;
 		P[2].y += -dx1h;
-		C[2] = Clipper::ComputeClipFlags(P[2]);
+		C[2] = Clipper::ComputeClipFlags(P[2], draw.depthClipEnable);
 
 		P[3].x += +dy0w;
 		P[3].y += -dx0h;
-		C[3] = Clipper::ComputeClipFlags(P[3]);
+		C[3] = Clipper::ComputeClipFlags(P[3], draw.depthClipEnable);
 
 		if((C[0] & C[1] & C[2] & C[3]) == Clipper::CLIP_FINITE)
 		{
@@ -958,28 +960,28 @@
 		float dy1 = lineWidth * 0.5f * P1.w / H;
 
 		P[0].x += -dx0;
-		C[0] = Clipper::ComputeClipFlags(P[0]);
+		C[0] = Clipper::ComputeClipFlags(P[0], draw.depthClipEnable);
 
 		P[1].y += +dy0;
-		C[1] = Clipper::ComputeClipFlags(P[1]);
+		C[1] = Clipper::ComputeClipFlags(P[1], draw.depthClipEnable);
 
 		P[2].x += +dx0;
-		C[2] = Clipper::ComputeClipFlags(P[2]);
+		C[2] = Clipper::ComputeClipFlags(P[2], draw.depthClipEnable);
 
 		P[3].y += -dy0;
-		C[3] = Clipper::ComputeClipFlags(P[3]);
+		C[3] = Clipper::ComputeClipFlags(P[3], draw.depthClipEnable);
 
 		P[4].x += -dx1;
-		C[4] = Clipper::ComputeClipFlags(P[4]);
+		C[4] = Clipper::ComputeClipFlags(P[4], draw.depthClipEnable);
 
 		P[5].y += +dy1;
-		C[5] = Clipper::ComputeClipFlags(P[5]);
+		C[5] = Clipper::ComputeClipFlags(P[5], draw.depthClipEnable);
 
 		P[6].x += +dx1;
-		C[6] = Clipper::ComputeClipFlags(P[6]);
+		C[6] = Clipper::ComputeClipFlags(P[6], draw.depthClipEnable);
 
 		P[7].y += -dy1;
-		C[7] = Clipper::ComputeClipFlags(P[7]);
+		C[7] = Clipper::ComputeClipFlags(P[7], draw.depthClipEnable);
 
 		if((C[0] & C[1] & C[2] & C[3] & C[4] & C[5] & C[6] & C[7]) == Clipper::CLIP_FINITE)
 		{
@@ -1112,10 +1114,10 @@
 			}
 		}
 
-		int C0 = Clipper::ComputeClipFlags(L[0]);
-		int C1 = Clipper::ComputeClipFlags(L[1]);
-		int C2 = Clipper::ComputeClipFlags(L[2]);
-		int C3 = Clipper::ComputeClipFlags(L[3]);
+		int C0 = Clipper::ComputeClipFlags(L[0], draw.depthClipEnable);
+		int C1 = Clipper::ComputeClipFlags(L[1], draw.depthClipEnable);
+		int C2 = Clipper::ComputeClipFlags(L[2], draw.depthClipEnable);
+		int C3 = Clipper::ComputeClipFlags(L[3], draw.depthClipEnable);
 
 		if((C0 & C1 & C2 & C3) == Clipper::CLIP_FINITE)
 		{
@@ -1166,19 +1168,19 @@
 
 	P[0].x -= X;
 	P[0].y += Y;
-	C[0] = Clipper::ComputeClipFlags(P[0]);
+	C[0] = Clipper::ComputeClipFlags(P[0], draw.depthClipEnable);
 
 	P[1].x += X;
 	P[1].y += Y;
-	C[1] = Clipper::ComputeClipFlags(P[1]);
+	C[1] = Clipper::ComputeClipFlags(P[1], draw.depthClipEnable);
 
 	P[2].x += X;
 	P[2].y -= Y;
-	C[2] = Clipper::ComputeClipFlags(P[2]);
+	C[2] = Clipper::ComputeClipFlags(P[2], draw.depthClipEnable);
 
 	P[3].x -= X;
 	P[3].y -= Y;
-	C[3] = Clipper::ComputeClipFlags(P[3]);
+	C[3] = Clipper::ComputeClipFlags(P[3], draw.depthClipEnable);
 
 	Polygon polygon(P, 4);
 
diff --git a/src/Device/Renderer.hpp b/src/Device/Renderer.hpp
index 2124e42..0252ed7 100644
--- a/src/Device/Renderer.hpp
+++ b/src/Device/Renderer.hpp
@@ -93,6 +93,7 @@
 	float constantDepthBias;
 	float slopeDepthBias;
 	float depthBiasClamp;
+	bool depthClipEnable;
 
 	unsigned int *colorBuffer[RENDERTARGETS];
 	int colorPitchB[RENDERTARGETS];
@@ -158,6 +159,8 @@
 	VkIndexType indexType;
 	VkLineRasterizationModeEXT lineRasterizationMode;
 
+	bool depthClipEnable;
+
 	VertexProcessor::RoutineType vertexRoutine;
 	SetupProcessor::RoutineType setupRoutine;
 	PixelProcessor::RoutineType pixelRoutine;
diff --git a/src/Device/VertexProcessor.cpp b/src/Device/VertexProcessor.cpp
index 1650639..68bdfc5 100644
--- a/src/Device/VertexProcessor.cpp
+++ b/src/Device/VertexProcessor.cpp
@@ -73,6 +73,7 @@
 	state.pipelineLayoutIdentifier = pipelineState.getPipelineLayout()->identifier;
 	state.robustBufferAccess = pipelineState.getRobustBufferAccess();
 	state.isPoint = pipelineState.getTopology() == VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
+	state.depthClipEnable = pipelineState.getDepthClipEnable();
 
 	for(size_t i = 0; i < MAX_INTERFACE_COMPONENTS / 4; i++)
 	{
diff --git a/src/Device/VertexProcessor.hpp b/src/Device/VertexProcessor.hpp
index aa1256e..f202434 100644
--- a/src/Device/VertexProcessor.hpp
+++ b/src/Device/VertexProcessor.hpp
@@ -81,6 +81,7 @@
 		Input input[MAX_INTERFACE_COMPONENTS / 4];
 		bool robustBufferAccess : 1;
 		bool isPoint : 1;
+		bool depthClipEnable : 1;
 	};
 
 	struct State : States
diff --git a/src/Pipeline/VertexRoutine.cpp b/src/Pipeline/VertexRoutine.cpp
index 737d755..8905fa8 100644
--- a/src/Pipeline/VertexRoutine.cpp
+++ b/src/Pipeline/VertexRoutine.cpp
@@ -125,17 +125,20 @@
 
 		Int4 maxX = CmpLT(posW, posX);
 		Int4 maxY = CmpLT(posW, posY);
-		Int4 maxZ = CmpLT(posW, posZ);
 		Int4 minX = CmpNLE(-posW, posX);
 		Int4 minY = CmpNLE(-posW, posY);
-		Int4 minZ = CmpNLE(Float4(0.0f), posZ);
 
 		clipFlags = Pointer<Int>(constants + OFFSET(Constants, maxX))[SignMask(maxX)];
 		clipFlags |= Pointer<Int>(constants + OFFSET(Constants, maxY))[SignMask(maxY)];
-		clipFlags |= Pointer<Int>(constants + OFFSET(Constants, maxZ))[SignMask(maxZ)];
 		clipFlags |= Pointer<Int>(constants + OFFSET(Constants, minX))[SignMask(minX)];
 		clipFlags |= Pointer<Int>(constants + OFFSET(Constants, minY))[SignMask(minY)];
-		clipFlags |= Pointer<Int>(constants + OFFSET(Constants, minZ))[SignMask(minZ)];
+		if(state.depthClipEnable)
+		{
+			Int4 maxZ = CmpLT(posW, posZ);
+			Int4 minZ = CmpNLE(Float4(0.0f), posZ);
+			clipFlags |= Pointer<Int>(constants + OFFSET(Constants, maxZ))[SignMask(maxZ)];
+			clipFlags |= Pointer<Int>(constants + OFFSET(Constants, minZ))[SignMask(minZ)];
+		}
 
 		Float4 maxPos = As<Float4>(Int4(0x7F7FFFFF));
 		Int4 finiteX = CmpLE(Abs(posX), maxPos);
diff --git a/src/Vulkan/VkPhysicalDevice.cpp b/src/Vulkan/VkPhysicalDevice.cpp
index bd12029..7e14d4b 100644
--- a/src/Vulkan/VkPhysicalDevice.cpp
+++ b/src/Vulkan/VkPhysicalDevice.cpp
@@ -319,6 +319,12 @@
 	features->subgroupBroadcastDynamicId = VK_TRUE;
 }
 
+template<typename T>
+static void getPhysicalDeviceDepthClipEnableFeaturesExt(T *features)
+{
+	features->depthClipEnable = VK_TRUE;
+}
+
 void PhysicalDevice::getFeatures2(VkPhysicalDeviceFeatures2 *features) const
 {
 	features->features = getFeatures();
@@ -405,6 +411,9 @@
 		case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES:
 			getPhysicalDeviceDescriptorIndexingFeatures(reinterpret_cast<VkPhysicalDeviceDescriptorIndexingFeatures *>(curExtension));
 			break;
+		case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT:
+			getPhysicalDeviceDepthClipEnableFeaturesExt(reinterpret_cast<VkPhysicalDeviceDepthClipEnableFeaturesEXT *>(curExtension));
+			break;
 		default:
 			LOG_TRAP("curExtension->pNext->sType = %s", vk::Stringify(curExtension->sType).c_str());
 			break;
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp
index 7555c69..6d53ce4 100644
--- a/src/Vulkan/libVulkan.cpp
+++ b/src/Vulkan/libVulkan.cpp
@@ -365,6 +365,7 @@
 	{ { VK_KHR_RELAXED_BLOCK_LAYOUT_EXTENSION_NAME, VK_KHR_RELAXED_BLOCK_LAYOUT_SPEC_VERSION } },
 	{ { VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME, VK_KHR_SAMPLER_YCBCR_CONVERSION_SPEC_VERSION } },
 	{ { VK_KHR_SEPARATE_DEPTH_STENCIL_LAYOUTS_EXTENSION_NAME, VK_KHR_SEPARATE_DEPTH_STENCIL_LAYOUTS_SPEC_VERSION } },
+	{ { VK_EXT_DEPTH_CLIP_ENABLE_EXTENSION_NAME, VK_EXT_DEPTH_CLIP_ENABLE_SPEC_VERSION} },
 	// Only 1.1 core version of this is supported. The extension has additional requirements
 	//{{ VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME, VK_KHR_SHADER_DRAW_PARAMETERS_SPEC_VERSION }},
 	{ { VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME, VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_SPEC_VERSION } },