Factor out GetTexelOffset from EmitImageRead/EmitImageWrite

Also fix the addressing to correctly use the slice pitch to advance to the correct layer in an arrayed 1D texture, rather than using the row pitch.

Bug: b/130768731
Test: dEQP-VK.image.*
Change-Id: I46b8c4eb353d7901d5953df46138ff9e01f87ead
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/29411
Tested-by: Chris Forbes <chrisforbes@google.com>
Presubmit-Ready: Chris Forbes <chrisforbes@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index 301c0d6..c5df163 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -4412,6 +4412,32 @@
 		return EmitResult::Continue;
 	}
 
+	SIMD::Int SpirvShader::GetTexelOffset(GenericValue const & coordinate, Type const & imageType, Pointer<Byte> descriptor, int texelSize) const
+	{
+		// returns a (lane-divergent) byte offset to a texel within a storage image.
+		bool isArrayed = imageType.definition.word(5) != 0;
+		int dims = getType(coordinate.type).sizeInComponents - (isArrayed ? 1 : 0);
+
+		SIMD::Int texelOffset = coordinate.Int(0) * SIMD::Int(texelSize);
+		if (dims > 1)
+		{
+			texelOffset += coordinate.Int(1) * SIMD::Int(
+					*Pointer<Int>(descriptor + OFFSET(vk::StorageImageDescriptor, rowPitchBytes)));
+		}
+		if (dims > 2)
+		{
+			texelOffset += coordinate.Int(2) * SIMD::Int(
+					*Pointer<Int>(descriptor + OFFSET(vk::StorageImageDescriptor, slicePitchBytes)));
+		}
+		if (isArrayed)
+		{
+			texelOffset += coordinate.Int(dims) * SIMD::Int(
+					*Pointer<Int>(descriptor + OFFSET(vk::StorageImageDescriptor, slicePitchBytes)));
+		}
+
+		return texelOffset;
+	}
+
 	SpirvShader::EmitResult SpirvShader::EmitImageRead(InsnIterator insn, EmitState *state) const
 	{
 		auto &resultType = getType(Type::ID(insn.word(1)));
@@ -4438,7 +4464,6 @@
 
 		auto &dst = state->routine->createIntermediate(resultId, resultType.sizeInComponents);
 
-
 		SIMD::Int packed[4];
 		auto numPackedElements = 0u;
 		int texelSize = 0;
@@ -4483,17 +4508,7 @@
 			UNIMPLEMENTED("spv::ImageFormat %u", format);
 		}
 
-		SIMD::Int texelOffset = coordinate.Int(0) * SIMD::Int(texelSize);
-		if (getType(coordinate.type).sizeInComponents > 1)
-		{
-			texelOffset += coordinate.Int(1) * SIMD::Int(
-					*Pointer<Int>(binding + OFFSET(vk::StorageImageDescriptor, rowPitchBytes)));
-		}
-		if (getType(coordinate.type).sizeInComponents > 2)
-		{
-			texelOffset += coordinate.Int(2) * SIMD::Int(
-					*Pointer<Int>(binding + OFFSET(vk::StorageImageDescriptor, slicePitchBytes)));
-		}
+		SIMD::Int texelOffset = GetTexelOffset(coordinate, imageType, binding, texelSize);
 
 		for (auto i = 0u; i < numPackedElements; i++)
 		{
@@ -4674,17 +4689,7 @@
 			UNIMPLEMENTED("spv::ImageFormat %u", format);
 		}
 
-		SIMD::Int texelOffset = coordinate.Int(0) * SIMD::Int(texelSize);
-		if (getType(coordinate.type).sizeInComponents > 1)
-		{
-			texelOffset += coordinate.Int(1) * SIMD::Int(
-					*Pointer<Int>(binding + OFFSET(vk::StorageImageDescriptor, rowPitchBytes)));
-		}
-		if (getType(coordinate.type).sizeInComponents > 2)
-		{
-			texelOffset += coordinate.Int(2) * SIMD::Int(
-					*Pointer<Int>(binding + OFFSET(vk::StorageImageDescriptor, slicePitchBytes)));
-		}
+		SIMD::Int texelOffset = GetTexelOffset(coordinate, imageType, binding, texelSize);
 
 		for (auto i = 0u; i < numPackedElements; i++)
 		{
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index e394db1..69dd01e 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -727,6 +727,8 @@
 		EmitResult EmitImageRead(InsnIterator insn, EmitState *state) const;
 		EmitResult EmitImageWrite(InsnIterator insn, EmitState *state) const;
 
+		SIMD::Int GetTexelOffset(GenericValue const & coordinate, Type const & imageType, Pointer<Byte> descriptor, int texelSize) const;
+
 		// OpcodeName() returns the name of the opcode op.
 		// If NDEBUG is defined, then OpcodeName() will only return the numerical code.
 		static std::string OpcodeName(spv::Op op);