Allow ImageView to cast compressed texture into other formats

If an image is created with flags including the
VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT
bit, then the compressed image may be used with
an image view which has an uncompressed format
that is size-compatible with the image's
compressed format.

Tests: dEQP-VK.image.texel_view_compatible.*.texture_read.e*

Bug b/119620767

Change-Id: Ia1af959780af12e9014f7852aaf991d313f75bf1
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/31620
Tested-by: Alexis Hétu <sugoi@google.com>
Presubmit-Ready: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
diff --git a/src/Vulkan/VkImage.cpp b/src/Vulkan/VkImage.cpp
index 9ac5ea6..cf44d68 100644
--- a/src/Vulkan/VkImage.cpp
+++ b/src/Vulkan/VkImage.cpp
@@ -706,6 +706,21 @@
 	return arrayLayers * getLayerSize(static_cast<VkImageAspectFlagBits>(aspectMask));
 }
 
+const Image* Image::getSampledImage(const vk::Format& imageViewFormat) const
+{
+	bool isImageViewCompressed = imageViewFormat.isCompressed();
+	if(decompressedImage && !isImageViewCompressed)
+	{
+		ASSERT(flags & VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT);
+		ASSERT(format.bytesPerBlock() == imageViewFormat.bytesPerBlock());
+	}
+	// If the ImageView's format is compressed, then we do need to decompress the image so that
+	// it may be sampled properly by texture sampling functions, which don't support compressed
+	// textures. If the ImageView's format is NOT compressed, then we reinterpret cast the
+	// compressed image into the ImageView's format, so we must return the compressed image as is.
+	return (decompressedImage && isImageViewCompressed) ? decompressedImage : this;
+}
+
 void Image::blit(VkImage dstImage, const VkImageBlit& region, VkFilter filter)
 {
 	device->getBlitter()->blit(this, Cast(dstImage), region, filter);
diff --git a/src/Vulkan/VkImage.hpp b/src/Vulkan/VkImage.hpp
index 86dae4c..b44332e 100644
--- a/src/Vulkan/VkImage.hpp
+++ b/src/Vulkan/VkImage.hpp
@@ -71,7 +71,7 @@
 	VkDeviceSize             getLayerSize(VkImageAspectFlagBits aspect) const;
 
 	void                     prepareForSampling(const VkImageSubresourceRange& subresourceRange);
-	const Image*             getSampledImage() const { return decompressedImage ? decompressedImage : this; }
+	const Image*             getSampledImage(const vk::Format& imageViewFormat) const;
 
 	static Format            GetFormat(const vk::Format& format, VkImageAspectFlagBits aspect);
 
diff --git a/src/Vulkan/VkImageView.cpp b/src/Vulkan/VkImageView.cpp
index 1cdad2b..512743c 100644
--- a/src/Vulkan/VkImageView.cpp
+++ b/src/Vulkan/VkImageView.cpp
@@ -192,7 +192,7 @@
 	case RAW:
 		return image;
 	case SAMPLING:
-		return image->getSampledImage();
+		return image->getSampledImage(format);
 	default:
 		UNIMPLEMENTED("usage %d", int(usage));
 		return nullptr;