Implement OpImageSampleExplicitLod

Emit a call to a different trampoline function for generating the
sampler code, which unifies the implementation with
OpImageSampleExplicitLod's by using a common EmitImageSample which
takes a sampler 'method' enum. This is then passed at shader execution
time to emitSamplerFunction.

The lod parameter is parsed from the instruction stream in
EmitImageSample. Other (optional) image operands are left unimplemented
for now.

Bug: b/129523279
Test: dEQP-VK.binding_model.shader_access.primary_cmd_buf.combined_image_sampler_mutable.fragment.single_descriptor.2d
Change-Id: I265b81d953fe5a0496d029704a0f5eeff4229823
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/29774
Tested-by: Nicolas Capens <nicolascapens@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Reviewed-by: Chris Forbes <chrisforbes@google.com>
diff --git a/src/Pipeline/SpirvShaderSampling.cpp b/src/Pipeline/SpirvShaderSampling.cpp
index 5921e55..d8bf659 100644
--- a/src/Pipeline/SpirvShaderSampling.cpp
+++ b/src/Pipeline/SpirvShaderSampling.cpp
@@ -39,14 +39,23 @@
 
 namespace sw {
 
-SpirvShader::ImageSampler *SpirvShader::getImageSampler(const vk::ImageView *imageView, const vk::Sampler *sampler)
+SpirvShader::ImageSampler *SpirvShader::getImageSamplerImplicitLod(const vk::ImageView *imageView, const vk::Sampler *sampler)
 {
-	// TODO: Move somewhere sensible.
+	return getImageSampler(Implicit, imageView, sampler);
+}
+SpirvShader::ImageSampler *SpirvShader::getImageSamplerExplicitLod(const vk::ImageView *imageView, const vk::Sampler *sampler)
+{
+	return getImageSampler(Lod, imageView, sampler);
+}
+
+SpirvShader::ImageSampler *SpirvShader::getImageSampler(SamplerMethod samplerMethod, const vk::ImageView *imageView, const vk::Sampler *sampler)
+{
+	// TODO(b/129523279): Move somewhere sensible.
 	static std::unordered_map<uintptr_t, ImageSampler*> cache;
 	static std::mutex mutex;
 
-	// TODO: Don't use pointers they can be deleted and reused, combine some two
-	// unique ids.
+	// FIXME(b/129523279): Don't use pointers: they can be deleted and reused. Instead combine some two unique ids.
+	// FIXME(b/129523279): Take instruction opcode and optional parameters into acount (SamplerMethod / SamplerOption).
 	auto key = reinterpret_cast<uintptr_t>(imageView) ^ reinterpret_cast<uintptr_t>(sampler);
 
 	std::unique_lock<std::mutex> lock(mutex);
@@ -58,13 +67,14 @@
 	Pointer<Byte> image = function.Arg<0>();
 	Pointer<SIMD::Float> in = function.Arg<1>();
 	Pointer<SIMD::Float> out = function.Arg<2>();
-	emitSamplerFunction(imageView, sampler, image, in, out);
+	emitSamplerFunction(samplerMethod, imageView, sampler, image, in, out);
 	auto fptr = reinterpret_cast<ImageSampler*>((void *)function("sampler")->getEntry());
 	cache.emplace(key, fptr);
 	return fptr;
 }
 
 void SpirvShader::emitSamplerFunction(
+        SamplerMethod samplerMethod,
         const vk::ImageView *imageView, const vk::Sampler *sampler,
         Pointer<Byte> image, Pointer<SIMD::Float> in, Pointer<Byte> out)
 {
@@ -102,11 +112,16 @@
 	Pointer<Byte> texture = image + OFFSET(vk::SampledImageDescriptor, texture);  // sw::Texture*
 	SIMD::Float w(0);     // TODO(b/129523279)
 	SIMD::Float q(0);     // TODO(b/129523279)
-	SIMD::Float bias(0);  // TODO(b/129523279)
+	SIMD::Float bias(0);
 	Vector4f dsx;         // TODO(b/129523279)
 	Vector4f dsy;         // TODO(b/129523279)
 	Vector4f offset;      // TODO(b/129523279)
-	SamplerFunction samplerFunction = { Implicit, None };  // ASSERT(insn.wordCount() == 5);  // TODO(b/129523279)
+	SamplerFunction samplerFunction = { samplerMethod, None };  // TODO(b/129523279)
+
+	if(samplerMethod == Lod)
+	{
+		bias = in[2];  // TODO(b/129523279): Index depends on view dimensions and other optional operands.
+	}
 
 	Vector4f sample = s.sampleTexture(texture, u, v, w, q, bias, dsx, dsy, offset, samplerFunction);