Implement OpImageSampleProjImplicitLod and OpImageSampleProjExplicitLod

Also add stubs for Dref variants.

Bug: b/129523279
Test: dEQP-VK.glsl.texture_functions.*
Test: dEQP-VK.spirv_assembly.instruction.graphics.image_sampler.*
Change-Id: I810c8e32758c9124f7649c62d51b34751ee9bfae
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/30193
Presubmit-Ready: Nicolas Capens <nicolascapens@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Chris Forbes <chrisforbes@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index 65a86b2..23499f9 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -842,6 +842,12 @@
 			case spv::OpPhi:
 			case spv::OpImageSampleImplicitLod:
 			case spv::OpImageSampleExplicitLod:
+			case spv::OpImageSampleDrefImplicitLod:
+			case spv::OpImageSampleDrefExplicitLod:
+			case spv::OpImageSampleProjImplicitLod:
+			case spv::OpImageSampleProjExplicitLod:
+			case spv::OpImageSampleProjDrefImplicitLod:
+			case spv::OpImageSampleProjDrefExplicitLod:
 			case spv::OpImageFetch:
 			case spv::OpImageQuerySize:
 			case spv::OpImageRead:
@@ -2386,10 +2392,28 @@
 			return EmitKill(insn, state);
 
 		case spv::OpImageSampleImplicitLod:
-			return EmitImageSampleImplicitLod(insn, state);
+			return EmitImageSampleImplicitLod(None, insn, state);
 
 		case spv::OpImageSampleExplicitLod:
-			return EmitImageSampleExplicitLod(insn, state);
+			return EmitImageSampleExplicitLod(None, insn, state);
+
+		case spv::OpImageSampleDrefImplicitLod:
+			return EmitImageSampleImplicitLod(Dref, insn, state);
+
+		case spv::OpImageSampleDrefExplicitLod:
+			return EmitImageSampleExplicitLod(Dref, insn, state);
+
+		case spv::OpImageSampleProjImplicitLod:
+			return EmitImageSampleImplicitLod(Proj, insn, state);
+
+		case spv::OpImageSampleProjExplicitLod:
+			return EmitImageSampleExplicitLod(Proj, insn, state);
+
+		case spv::OpImageSampleProjDrefImplicitLod:
+			return EmitImageSampleImplicitLod(ProjDref, insn, state);
+
+		case spv::OpImageSampleProjDrefExplicitLod:
+			return EmitImageSampleExplicitLod(ProjDref, insn, state);
 
 		case spv::OpImageFetch:
 			return EmitImageFetch(insn, state);
@@ -4457,22 +4481,22 @@
 		return EmitResult::Continue;
 	}
 
-	SpirvShader::EmitResult SpirvShader::EmitImageSampleImplicitLod(InsnIterator insn, EmitState *state) const
+	SpirvShader::EmitResult SpirvShader::EmitImageSampleImplicitLod(Variant variant, InsnIterator insn, EmitState *state) const
 	{
-		return EmitImageSample({Implicit}, insn, state);
+		return EmitImageSample({variant, Implicit}, insn, state);
 	}
 
-	SpirvShader::EmitResult SpirvShader::EmitImageSampleExplicitLod(InsnIterator insn, EmitState *state) const
+	SpirvShader::EmitResult SpirvShader::EmitImageSampleExplicitLod(Variant variant, InsnIterator insn, EmitState *state) const
 	{
 		uint32_t imageOperands = static_cast<spv::ImageOperandsMask>(insn.word(5));
 
 		if((imageOperands & spv::ImageOperandsLodMask) == imageOperands)
 		{
-			return EmitImageSample({Lod}, insn, state);
+			return EmitImageSample({variant, Lod}, insn, state);
 		}
 		else if((imageOperands & spv::ImageOperandsGradMask) == imageOperands)
 		{
-			return EmitImageSample({Grad}, insn, state);
+			return EmitImageSample({variant, Grad}, insn, state);
 		}
 		else UNIMPLEMENTED("Image Operands %x", imageOperands);
 		return EmitResult::Continue;
@@ -4569,10 +4593,25 @@
 
 		Array<SIMD::Float> in(16);  // Maximum 16 input parameter components.
 
+		uint32_t coordinates = coordinateType.sizeInComponents - instruction.isProj();
+		instruction.coordinates = coordinates;
+
 		uint32_t i = 0;
-		for( ; i < coordinateType.sizeInComponents; i++)
+		for( ; i < coordinates; i++)
 		{
-			in[i] = coordinate.Float(i);
+			if(instruction.isProj())
+			{
+				in[i] = coordinate.Float(i) / coordinate.Float(coordinates);  // TODO(b/129523279): Optimize using reciprocal.
+			}
+			else
+			{
+				in[i] = coordinate.Float(i);
+			}
+		}
+
+		if(instruction.isDref())
+		{
+			UNIMPLEMENTED("OpImageSample*Dref*");  // TODO(b/129523279)
 		}
 
 		if(lod)
@@ -4615,8 +4654,6 @@
 			}
 		}
 
-		instruction.coordinates = coordinateType.sizeInComponents;
-
 		auto samplerFunc = Call(getImageSampler, instruction.parameters, imageView, sampler);
 
 		Array<SIMD::Float> out(4);
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index c97d690..1d09f88 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -466,12 +466,25 @@
 			inline operator Object::ID() const { return Object::ID(value()); }
 		};
 
+		// OpImageSample variants
+		enum Variant
+		{
+			None,
+			Dref,
+			Proj,
+			ProjDref,
+			VARIANT_LAST = ProjDref
+		};
+
 		// Compact representation of image instruction parameters that is passed to the
 		// trampoline function for retrieving/generating the corresponding sampling routine.
 		struct ImageInstruction
 		{
-			ImageInstruction(SamplerMethod samplerMethod) : samplerMethod(samplerMethod)
+			ImageInstruction(Variant variant, SamplerMethod samplerMethod)
+				: parameters(0)
 			{
+				this->variant = variant;
+				this->samplerMethod = samplerMethod;
 			}
 
 			// Unmarshal from raw 32-bit data
@@ -482,18 +495,32 @@
 				return { static_cast<SamplerMethod>(samplerMethod), static_cast<SamplerOption>(samplerOption) };
 			}
 
+			bool isDref() const
+			{
+				return (variant == Dref) || (variant == ProjDref);
+			}
+
+			bool isProj() const
+			{
+				return (variant == Proj) || (variant == ProjDref);
+			}
+
 			union
 			{
 				struct
 				{
+					uint32_t variant : BITS(VARIANT_LAST);
 					uint32_t samplerMethod : BITS(SAMPLER_METHOD_LAST);
 					uint32_t samplerOption : BITS(SAMPLER_OPTION_LAST);
-					uint32_t coordinates : 3;       // 1-4
+
+					// Parameters are passed to the sampling routine in this order:
+					uint32_t coordinates : 3;       // 1-4 (does not contain projection component)
+				//	uint32_t lod : 1;               // Indicated by SamplerMethod::Lod
 					uint32_t gradComponents : 2;    // 0-3 (for each of dx / dy)
 					uint32_t offsetComponents : 2;  // 0-3
 				};
 
-				uint32_t parameters = 0;
+				uint32_t parameters;
 			};
 		};
 
@@ -867,8 +894,8 @@
 		EmitResult EmitReturn(InsnIterator insn, EmitState *state) const;
 		EmitResult EmitKill(InsnIterator insn, EmitState *state) const;
 		EmitResult EmitPhi(InsnIterator insn, EmitState *state) const;
-		EmitResult EmitImageSampleImplicitLod(InsnIterator insn, EmitState *state) const;
-		EmitResult EmitImageSampleExplicitLod(InsnIterator insn, EmitState *state) const;
+		EmitResult EmitImageSampleImplicitLod(Variant variant, InsnIterator insn, EmitState *state) const;
+		EmitResult EmitImageSampleExplicitLod(Variant variant, InsnIterator insn, EmitState *state) const;
 		EmitResult EmitImageFetch(InsnIterator insn, EmitState *state) const;
 		EmitResult EmitImageSample(ImageInstruction instruction, InsnIterator insn, EmitState *state) const;
 		EmitResult EmitImageQuerySize(InsnIterator insn, EmitState *state) const;