Support selection of correct aspect for D+S input attachments

Test: dEQP-VK.*d32_sfloat_s8_uint*
Bug: b/123244275
Bug: b/131171141
Change-Id: Ic13fee99754e78619c7769000a666c90a5c56218
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/30748
Tested-by: Chris Forbes <chrisforbes@google.com>
Presubmit-Ready: Chris Forbes <chrisforbes@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index 2c912c7..b3baaba 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -4756,7 +4756,7 @@
 		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) const
+	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;
 		auto dim = static_cast<spv::Dim>(imageType.definition.word(3));
@@ -4770,28 +4770,44 @@
 			v += routine->windowSpacePosition[1];
 		}
 
+		if (useStencilAspect)
+		{
+			// Adjust addressing for quad layout. Pitches are already correct for the stencil aspect.
+			// In the quad-layout block, pixel order is [x0,y0   x1,y0   x0,y1   x1,y1]
+			u = ((v & SIMD::Int(1)) << 1) | ((u << 1) - (u & SIMD::Int(1)));
+			v &= SIMD::Int(~1);
+		}
+
+		auto rowPitch = SIMD::Int(*Pointer<Int>(descriptor + (useStencilAspect
+															  ? OFFSET(vk::StorageImageDescriptor, stencilRowPitchBytes)
+															  : OFFSET(vk::StorageImageDescriptor, rowPitchBytes))));
+		auto slicePitch = SIMD::Int(
+				*Pointer<Int>(descriptor + (useStencilAspect
+											? OFFSET(vk::StorageImageDescriptor, stencilSlicePitchBytes)
+											: OFFSET(vk::StorageImageDescriptor, slicePitchBytes))));
+		auto samplePitch = SIMD::Int(
+				*Pointer<Int>(descriptor + (useStencilAspect
+											? OFFSET(vk::StorageImageDescriptor, stencilSamplePitchBytes)
+											: OFFSET(vk::StorageImageDescriptor, samplePitchBytes))));
+
 		ptr += u * SIMD::Int(texelSize);
 		if (dims > 1)
 		{
-			ptr += v * SIMD::Int(
-					*Pointer<Int>(descriptor + OFFSET(vk::StorageImageDescriptor, rowPitchBytes)));
+			ptr += v * rowPitch;
 		}
 		if (dims > 2)
 		{
-			ptr += coordinate.Int(2) * SIMD::Int(
-					*Pointer<Int>(descriptor + OFFSET(vk::StorageImageDescriptor, slicePitchBytes)));
+			ptr += coordinate.Int(2) * slicePitch;
 		}
 		if (isArrayed)
 		{
-			ptr += coordinate.Int(dims) * SIMD::Int(
-					*Pointer<Int>(descriptor + OFFSET(vk::StorageImageDescriptor, slicePitchBytes)));
+			ptr += coordinate.Int(dims) * slicePitch;
 		}
 
 		if (sampleId.value())
 		{
 			GenericValue sample{this, routine, sampleId};
-			ptr += sample.Int(0) * SIMD::Int(
-					*Pointer<Int>(descriptor + OFFSET(vk::StorageImageDescriptor, samplePitchBytes)));
+			ptr += sample.Int(0) * samplePitch;
 		}
 
 		return ptr;
@@ -4825,23 +4841,37 @@
 		auto dim = static_cast<spv::Dim>(imageType.definition.word(3));
 
 		auto coordinate = GenericValue(this, state->routine, insn.word(4));
-
-		auto pointer = state->routine->getPointer(imageId);
-		Pointer<Byte> binding = pointer.base;
-		Pointer<Byte> imageBase = *Pointer<Pointer<Byte>>(binding + OFFSET(vk::StorageImageDescriptor, ptr));
 		const DescriptorDecorations &d = descriptorDecorations.at(imageId);
-		auto imageSizeInBytes = *Pointer<Int>(binding + OFFSET(vk::StorageImageDescriptor, sizeInBytes));
-
-		auto &dst = state->routine->createIntermediate(resultId, resultType.sizeInComponents);
 
 		// For subpass data, format in the instruction is spv::ImageFormatUnknown. Get it from
 		// the renderpass data instead. In all other cases, we can use the format in the instruction.
 		auto vkFormat = (dim == spv::DimSubpassData)
 						? inputAttachmentFormats[d.InputAttachmentIndex]
 						: SpirvFormatToVulkanFormat(static_cast<spv::ImageFormat>(imageType.definition.word(8)));
+
+		// Depth+Stencil image attachments select aspect based on the Sampled Type of the
+		// OpTypeImage. If float, then we want the depth aspect. If int, we want the stencil aspect.
+		auto useStencilAspect = (vkFormat == VK_FORMAT_D32_SFLOAT_S8_UINT &&
+				getType(imageType.definition.word(2)).opcode() == spv::OpTypeInt);
+
+		if (useStencilAspect)
+		{
+			vkFormat = VK_FORMAT_S8_UINT;
+		}
+
+		auto pointer = state->routine->getPointer(imageId);
+		Pointer<Byte> binding = pointer.base;
+		Pointer<Byte> imageBase = *Pointer<Pointer<Byte>>(binding + (useStencilAspect
+				? OFFSET(vk::StorageImageDescriptor, stencilPtr)
+				: OFFSET(vk::StorageImageDescriptor, ptr)));
+
+		auto imageSizeInBytes = *Pointer<Int>(binding + OFFSET(vk::StorageImageDescriptor, sizeInBytes));
+
+		auto &dst = state->routine->createIntermediate(resultId, resultType.sizeInComponents);
+
 		auto texelSize = vk::Format(vkFormat).bytes();
 		auto basePtr = SIMD::Pointer(imageBase, imageSizeInBytes);
-		auto texelPtr = GetTexelAddress(state->routine, basePtr, coordinate, imageType, binding, texelSize, sampleId);
+		auto texelPtr = GetTexelAddress(state->routine, basePtr, coordinate, imageType, binding, texelSize, sampleId, useStencilAspect);
 
 		SIMD::Int packed[4];
 		// Round up texel size: for formats smaller than 32 bits per texel, we will emit a bunch
@@ -4876,7 +4906,7 @@
 			break;
 		case VK_FORMAT_R32_SFLOAT:
 		case VK_FORMAT_D32_SFLOAT:
-		//case VK_FORMAT_D32_SFLOAT_S8_UINT:
+		case VK_FORMAT_D32_SFLOAT_S8_UINT:
 			dst.move(0, packed[0]);
 			// Fill remaining channels with 0,0,1 (of the correct type)
 			dst.move(1, SIMD::Float(0));
@@ -4960,6 +4990,7 @@
 			dst.move(3, SIMD::Float(1));
 			break;
 		case VK_FORMAT_R8_UINT:
+		case VK_FORMAT_S8_UINT:
 			dst.move(0, (As<SIMD::UInt>(packed[0]) & SIMD::UInt(0xFF)));
 			dst.move(1, SIMD::UInt(0));
 			dst.move(2, SIMD::UInt(0));
@@ -5176,7 +5207,7 @@
 		}
 
 		auto basePtr = SIMD::Pointer(imageBase, imageSizeInBytes);
-		auto texelPtr = GetTexelAddress(state->routine, basePtr, coordinate, imageType, binding, texelSize, 0);
+		auto texelPtr = GetTexelAddress(state->routine, basePtr, coordinate, imageType, binding, texelSize, 0, false);
 
 		for (auto i = 0u; i < numPackedElements; i++)
 		{
@@ -5208,7 +5239,7 @@
 		auto imageSizeInBytes = *Pointer<Int>(binding + OFFSET(vk::StorageImageDescriptor, sizeInBytes));
 
 		auto basePtr = SIMD::Pointer(imageBase, imageSizeInBytes);
-		auto ptr = GetTexelAddress(state->routine, basePtr, coordinate, imageType, binding, sizeof(uint32_t), 0);
+		auto ptr = GetTexelAddress(state->routine, basePtr, coordinate, imageType, binding, sizeof(uint32_t), 0, false);
 
 		state->routine->createPointer(resultId, ptr);
 
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index b893073..de4c03b 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -909,7 +909,7 @@
 		EmitResult EmitCopyMemory(InsnIterator insn, EmitState *state) const;
 		EmitResult EmitGroupNonUniform(InsnIterator insn, EmitState *state) const;
 
-		SIMD::Pointer GetTexelAddress(SpirvRoutine const * routine, SIMD::Pointer base, GenericValue const & coordinate, Type const & imageType, Pointer<Byte> descriptor, int texelSize, Object::ID sampleId) const;
+		SIMD::Pointer GetTexelAddress(SpirvRoutine const * routine, SIMD::Pointer base, GenericValue const & coordinate, Type const & imageType, Pointer<Byte> descriptor, int texelSize, Object::ID sampleId, bool useStencilAspect) const;
 		spv::Scope GetScope(Object::ID id) const;
 
 		// OpcodeName() returns the name of the opcode op.
diff --git a/src/Vulkan/VkDescriptorSetLayout.cpp b/src/Vulkan/VkDescriptorSetLayout.cpp
index d44bbab..e0b9346 100644
--- a/src/Vulkan/VkDescriptorSetLayout.cpp
+++ b/src/Vulkan/VkDescriptorSetLayout.cpp
@@ -496,6 +496,16 @@
 			descriptor[i].slicePitchBytes = descriptor[i].samplePitchBytes * imageView->getSampleCount();
 			descriptor[i].arrayLayers = imageView->getSubresourceRange().layerCount;
 			descriptor[i].sizeInBytes = imageView->getImageSizeInBytes();
+
+			if (imageView->getFormat().isStencil())
+			{
+				descriptor[i].stencilPtr = imageView->getOffsetPointer({0, 0, 0}, VK_IMAGE_ASPECT_STENCIL_BIT, 0, 0);
+				descriptor[i].stencilRowPitchBytes = imageView->rowPitchBytes(VK_IMAGE_ASPECT_STENCIL_BIT, 0);
+				descriptor[i].stencilSamplePitchBytes = imageView->getSubresourceRange().layerCount > 1
+												 ? imageView->layerPitchBytes(VK_IMAGE_ASPECT_STENCIL_BIT)
+												 : imageView->slicePitchBytes(VK_IMAGE_ASPECT_STENCIL_BIT, 0);
+				descriptor[i].stencilSlicePitchBytes = descriptor[i].stencilSamplePitchBytes * imageView->getSampleCount();
+			}
 		}
 	}
 	else if (entry.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)
diff --git a/src/Vulkan/VkDescriptorSetLayout.hpp b/src/Vulkan/VkDescriptorSetLayout.hpp
index 38722d5..4a1a444 100644
--- a/src/Vulkan/VkDescriptorSetLayout.hpp
+++ b/src/Vulkan/VkDescriptorSetLayout.hpp
@@ -47,6 +47,11 @@
 	int samplePitchBytes;
 	int arrayLayers;
 	int sizeInBytes;
+
+	void *stencilPtr;
+	int stencilRowPitchBytes;
+	int stencilSlicePitchBytes;
+	int stencilSamplePitchBytes;
 };
 
 struct alignas(16) BufferDescriptor