Plumb through Dref parameter to sampler

Bug: b/129523279
Test: dEQP-VK.texture.shadow.*
Test: dEQP-VK.glsl.*
Change-Id: I7e8241cb458200aeabb22992c02f0feb86479ac2
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/30649
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Tested-by: Chris Forbes <chrisforbes@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
diff --git a/src/Device/Sampler.hpp b/src/Device/Sampler.hpp
index 752d018..c306494 100644
--- a/src/Device/Sampler.hpp
+++ b/src/Device/Sampler.hpp
@@ -150,7 +150,8 @@
 		MipmapType mipmapFilter;
 		VkComponentMapping swizzle;
 		bool highPrecisionFiltering;
-		CompareFunc compare;
+		bool compareEnable;
+		VkCompareOp compareOp;
 		VkBorderColor border;
 
 		#if PERF_PROFILE
diff --git a/src/Pipeline/SamplerCore.cpp b/src/Pipeline/SamplerCore.cpp
index 9e2c952..2c0cbf6 100644
--- a/src/Pipeline/SamplerCore.cpp
+++ b/src/Pipeline/SamplerCore.cpp
@@ -130,11 +130,11 @@
 		bool forceFloatFiltering = state.highPrecisionFiltering && !hasYuvFormat() && (state.textureFilter != FILTER_POINT);
 		bool seamlessCube = (state.addressingModeU == ADDRESSING_SEAMLESS);
 		bool rectangleTexture = (state.textureType == TEXTURE_RECTANGLE);
-		if(hasFloatTexture() || hasUnnormalizedIntegerTexture() || forceFloatFiltering || seamlessCube || rectangleTexture)   // FIXME: Mostly identical to integer sampling
+		if(hasFloatTexture() || hasUnnormalizedIntegerTexture() || forceFloatFiltering || seamlessCube || rectangleTexture || state.compareEnable)   // FIXME: Mostly identical to integer sampling
 		{
 			c = sampleFloatFilter(texture, uuuu, vvvv, wwww, qqqq, offset, lod, anisotropy, uDelta, vDelta, face, function);
 
-			if(!hasFloatTexture() && !hasUnnormalizedIntegerTexture())
+			if(!hasFloatTexture() && !hasUnnormalizedIntegerTexture() && !state.compareEnable)
 			{
 				if(has16bitTextureFormat())
 				{
@@ -1993,27 +1993,29 @@
 			}
 		}
 
-		if(state.compare != COMPARE_BYPASS)
+		if(state.compareEnable)
 		{
 			Float4 ref = z;
 
 			if(!hasFloatTexture())
 			{
+				// D16_UNORM: clamp reference, normalize texel value
 				ref = Min(Max(ref, Float4(0.0f)), Float4(1.0f));
+				c.x = c.x * Float4(1.0f / 0xFFFF);
 			}
 
 			Int4 boolean;
 
-			switch(state.compare)
+			switch(state.compareOp)
 			{
-			case COMPARE_LESSEQUAL:    boolean = CmpLE(ref, c.x);  break;
-			case COMPARE_GREATEREQUAL: boolean = CmpNLT(ref, c.x); break;
-			case COMPARE_LESS:         boolean = CmpLT(ref, c.x);  break;
-			case COMPARE_GREATER:      boolean = CmpNLE(ref, c.x); break;
-			case COMPARE_EQUAL:        boolean = CmpEQ(ref, c.x);  break;
-			case COMPARE_NOTEQUAL:     boolean = CmpNEQ(ref, c.x); break;
-			case COMPARE_ALWAYS:       boolean = Int4(-1);         break;
-			case COMPARE_NEVER:        boolean = Int4(0);          break;
+			case VK_COMPARE_OP_LESS_OR_EQUAL:    boolean = CmpLE(ref, c.x);  break;
+			case VK_COMPARE_OP_GREATER_OR_EQUAL: boolean = CmpNLT(ref, c.x); break;
+			case VK_COMPARE_OP_LESS:             boolean = CmpLT(ref, c.x);  break;
+			case VK_COMPARE_OP_GREATER:          boolean = CmpNLE(ref, c.x); break;
+			case VK_COMPARE_OP_EQUAL:            boolean = CmpEQ(ref, c.x);  break;
+			case VK_COMPARE_OP_NOT_EQUAL:        boolean = CmpNEQ(ref, c.x); break;
+			case VK_COMPARE_OP_ALWAYS:           boolean = Int4(-1);         break;
+			case VK_COMPARE_OP_NEVER:            boolean = Int4(0);          break;
 			default:                   ASSERT(false);
 			}
 
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index 1a8a261..16a4d73 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -4578,10 +4578,11 @@
 		Object::ID offsetId = 0;
 		bool sample = false;
 
-		if(insn.wordCount() > 5)
+		uint32_t operand = instruction.isDref() ? 6 : 5;
+
+		if(insn.wordCount() > operand)
 		{
-			imageOperands = static_cast<spv::ImageOperandsMask>(insn.word(5));
-			uint32_t operand = 6;
+			imageOperands = static_cast<spv::ImageOperandsMask>(insn.word(operand++));
 
 			if(imageOperands & spv::ImageOperandsBiasMask)
 			{
@@ -4653,7 +4654,9 @@
 
 		if(instruction.isDref())
 		{
-			UNIMPLEMENTED("OpImageSample*Dref*");  // TODO(b/129523279)
+			auto drefValue = GenericValue(this, state->routine, insn.word(5));
+			in[i] = drefValue.Float(0);
+			i++;
 		}
 
 		if(lodOrBias)
@@ -4701,7 +4704,7 @@
 		Array<SIMD::Float> out(4);
 		Call<ImageSampler>(samplerFunc, texture, sampler, &in[0], &out[0], state->routine->constants);
 
-		for (int i = 0; i < 4; i++) { result.move(i, out[i]); }
+		for (auto i = 0u; i < resultType.sizeInComponents; i++) { result.move(i, out[i]); }
 
 		return EmitResult::Continue;
 	}
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index b8f1c50..265749b 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -515,6 +515,7 @@
 
 					// Parameters are passed to the sampling routine in this order:
 					uint32_t coordinates : 3;       // 1-4 (does not contain projection component)
+				//  uint32_t dref : 1;				// Indicated by Variant::ProjDref|Dref
 				//	uint32_t lodOrBias : 1;         // Indicated by SamplerMethod::Lod|Bias
 					uint32_t gradComponents : 2;    // 0-3 (for each of dx / dy)
 					uint32_t offsetComponents : 2;  // 0-3
diff --git a/src/Pipeline/SpirvShaderSampling.cpp b/src/Pipeline/SpirvShaderSampling.cpp
index af7c494..7ea5bfc 100644
--- a/src/Pipeline/SpirvShaderSampling.cpp
+++ b/src/Pipeline/SpirvShaderSampling.cpp
@@ -66,7 +66,8 @@
 	samplerState.mipmapFilter = convertMipmapMode(sampler);
 	samplerState.swizzle = imageView->getComponentMapping();
 	samplerState.highPrecisionFiltering = false;
-	samplerState.compare = COMPARE_BYPASS;                  ASSERT(sampler->compareEnable == VK_FALSE);  // TODO(b/129523279)
+	samplerState.compareEnable = (sampler->compareEnable == VK_TRUE);
+	samplerState.compareOp = sampler->compareOp;
 
 	ASSERT(sampler->anisotropyEnable == VK_FALSE);  // TODO(b/129523279)
 	ASSERT(sampler->unnormalizedCoordinates == VK_FALSE);  // TODO(b/129523279)
@@ -104,6 +105,12 @@
 			uvw[i] = in[i];
 		}
 
+		if (instruction.isDref())
+		{
+			q = in[i];
+			i++;
+		}
+
 		// TODO(b/129523279): Currently 1D textures are treated as 2D by setting the second coordinate to 0.
 		// Implement optimized 1D sampling.
 		if(samplerState.textureType == TEXTURE_1D ||
diff --git a/src/Vulkan/VkFormat.cpp b/src/Vulkan/VkFormat.cpp
index d1debf4..0c41831 100644
--- a/src/Vulkan/VkFormat.cpp
+++ b/src/Vulkan/VkFormat.cpp
@@ -1945,6 +1945,7 @@
 	case VK_FORMAT_A2B10G10R10_UINT_PACK32:
 	case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
 	case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
+	case VK_FORMAT_D16_UNORM:
 		return false;
 	case VK_FORMAT_R32_SINT:
 	case VK_FORMAT_R32_UINT: