SpirvShader: Implement OpImageQuerySamples

Tests: dEQP-VK.glsl.texture_functions.query.texturesamples.*
Bug: b/129523279
Change-Id: I17008f03f5e86313249b4bcb061b8b3f16e56b19
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/31112
Presubmit-Ready: Ben Clayton <bclayton@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
Reviewed-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 30eaf96..f59ce6b 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -902,6 +902,7 @@
 			case spv::OpImageQuerySize:
 			case spv::OpImageQuerySizeLod:
 			case spv::OpImageQueryLevels:
+			case spv::OpImageQuerySamples:
 			case spv::OpImageRead:
 			case spv::OpImageTexelPointer:
 			case spv::OpGroupNonUniformElect:
@@ -2495,6 +2496,9 @@
 		case spv::OpImageQueryLevels:
 			return EmitImageQueryLevels(insn, state);
 
+		case spv::OpImageQuerySamples:
+			return EmitImageQuerySamples(insn, state);
+
 		case spv::OpImageRead:
 			return EmitImageRead(insn, state);
 
@@ -4918,10 +4922,8 @@
 		case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
 		case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
 		case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
-		{
 			mipLevels = *Pointer<Int>(descriptor + OFFSET(vk::SampledImageDescriptor, mipLevels)); // uint32_t
 			break;
-		}
 		default:
 			UNREACHABLE("Image descriptorType: %d", int(bindingLayout.descriptorType));
 		}
@@ -4932,6 +4934,43 @@
 		return EmitResult::Continue;
 	}
 
+	SpirvShader::EmitResult SpirvShader::EmitImageQuerySamples(InsnIterator insn, EmitState *state) const
+	{
+		auto &resultTy = getType(Type::ID(insn.word(1)));
+		ASSERT(resultTy.sizeInComponents == 1);
+		auto resultId = Object::ID(insn.word(2));
+		auto imageId = Object::ID(insn.word(3));
+		auto imageTy = getType(getObject(imageId).type);
+		ASSERT(imageTy.definition.opcode() == spv::OpTypeImage);
+		ASSERT(imageTy.definition.word(3) == spv::Dim2D);
+		ASSERT(imageTy.definition.word(6 /* MS */) == 1);
+
+		const DescriptorDecorations &d = descriptorDecorations.at(imageId);
+		auto setLayout = state->routine->pipelineLayout->getDescriptorSetLayout(d.DescriptorSet);
+		auto &bindingLayout = setLayout->getBindingLayout(d.Binding);
+
+		Pointer<Byte> descriptor = state->routine->getPointer(imageId).base;
+		Int sampleCount = 0;
+		switch (bindingLayout.descriptorType)
+		{
+		case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+			sampleCount = *Pointer<Int>(descriptor + OFFSET(vk::StorageImageDescriptor, sampleCount)); // uint32_t
+			break;
+		case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+		case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+		case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
+			sampleCount = *Pointer<Int>(descriptor + OFFSET(vk::SampledImageDescriptor, sampleCount)); // uint32_t
+			break;
+		default:
+			UNREACHABLE("Image descriptorType: %d", int(bindingLayout.descriptorType));
+		}
+
+		auto &dst = state->routine->createIntermediate(resultId, 1);
+		dst.move(0, SIMD::Int(sampleCount));
+
+		return EmitResult::Continue;
+	}
+
 	SIMD::Pointer SpirvShader::GetTexelAddress(SpirvRoutine const *routine, SIMD::Pointer ptr, GenericValue const & coordinate, Type const & imageType, Pointer<Byte> descriptor, int texelSize, Object::ID sampleId, bool useStencilAspect) const
 	{
 		bool isArrayed = imageType.definition.word(5) != 0;
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index 2c98e4f..58c3063 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -942,6 +942,7 @@
 		EmitResult EmitImageQuerySize(InsnIterator insn, EmitState *state) const;
 		EmitResult EmitImageQuerySizeLod(InsnIterator insn, EmitState *state) const;
 		EmitResult EmitImageQueryLevels(InsnIterator insn, EmitState *state) const;
+		EmitResult EmitImageQuerySamples(InsnIterator insn, EmitState *state) const;
 		EmitResult EmitImageRead(InsnIterator insn, EmitState *state) const;
 		EmitResult EmitImageWrite(InsnIterator insn, EmitState *state) const;
 		EmitResult EmitImageTexelPointer(InsnIterator insn, EmitState *state) const;
diff --git a/src/Vulkan/VkDescriptorSetLayout.cpp b/src/Vulkan/VkDescriptorSetLayout.cpp
index dfb8362..8ea47e6 100644
--- a/src/Vulkan/VkDescriptorSetLayout.cpp
+++ b/src/Vulkan/VkDescriptorSetLayout.cpp
@@ -315,6 +315,7 @@
 			imageSampler[i].extent = { numElements, 1, 1 };
 			imageSampler[i].arrayLayers = 1;
 			imageSampler[i].mipLevels = 1;
+			imageSampler[i].sampleCount = 1;
 			imageSampler[i].texture.widthWidthHeightHeight = sw::vector(numElements, numElements, 1, 1);
 			imageSampler[i].texture.width = sw::replicate(numElements);
 			imageSampler[i].texture.height = sw::replicate(1);
@@ -353,6 +354,7 @@
 			imageSampler[i].extent = imageView->getMipLevelExtent(0);
 			imageSampler[i].arrayLayers = imageView->getSubresourceRange().layerCount;
 			imageSampler[i].mipLevels = imageView->getSubresourceRange().levelCount;
+			imageSampler[i].sampleCount = imageView->getSampleCount();
 			imageSampler[i].type = imageView->getType();
 			imageSampler[i].swizzle = imageView->getComponentMapping();
 			imageSampler[i].format = imageView->getFormat(ImageView::SAMPLING);
@@ -531,6 +533,7 @@
 											 : imageView->slicePitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0);
 			descriptor[i].slicePitchBytes = descriptor[i].samplePitchBytes * imageView->getSampleCount();
 			descriptor[i].arrayLayers = imageView->getSubresourceRange().layerCount;
+			descriptor[i].sampleCount = imageView->getSampleCount();
 			descriptor[i].sizeInBytes = imageView->getImageSizeInBytes();
 
 			if (imageView->getFormat().isStencil())
@@ -557,6 +560,7 @@
 			descriptor[i].slicePitchBytes = 0;
 			descriptor[i].samplePitchBytes = 0;
 			descriptor[i].arrayLayers = 1;
+			descriptor[i].sampleCount = 1;
 			descriptor[i].sizeInBytes = bufferView->getRangeInBytes();
 		}
 	}
diff --git a/src/Vulkan/VkDescriptorSetLayout.hpp b/src/Vulkan/VkDescriptorSetLayout.hpp
index c368b1d..dd14de3 100644
--- a/src/Vulkan/VkDescriptorSetLayout.hpp
+++ b/src/Vulkan/VkDescriptorSetLayout.hpp
@@ -42,6 +42,7 @@
 	VkExtent3D extent; // Of base mip-level.
 	int arrayLayers;
 	int mipLevels;
+	int sampleCount;
 };
 
 struct alignas(16) StorageImageDescriptor
@@ -52,6 +53,7 @@
 	int slicePitchBytes;
 	int samplePitchBytes;
 	int arrayLayers;
+	int sampleCount;
 	int sizeInBytes;
 
 	void *stencilPtr;