Vulkan: Texture 3D and 2DArray layers as framebuffer attachments

Support glFramebufferTextureLayer by correctly handling layers
from 3D and 2DArray textures.  Modeled after CubeMap layers support.

Bug: angleproject:3188
Bug: angleproject:3189
Change-Id: Ic73a6017134e9d2b49beed103487454397a97167
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1738436
Reviewed-by: Tim Van Patten <timvp@google.com>
Commit-Queue: Cody Northrop <cnorthrop@google.com>
diff --git a/src/libANGLE/renderer/vulkan/FramebufferVk.cpp b/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
index eee1d58..dae582c 100644
--- a/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
+++ b/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
@@ -1439,9 +1439,23 @@
     size_t level         = renderTarget->getLevelIndex();
     size_t layer         = renderTarget->getLayerIndex();
     VkOffset3D srcOffset = {area.x, area.y, 0};
+
+    VkImageSubresourceLayers srcSubresource = {};
+    srcSubresource.aspectMask               = copyAspectFlags;
+    srcSubresource.mipLevel                 = level;
+    srcSubresource.baseArrayLayer           = layer;
+    srcSubresource.layerCount               = 1;
+
     VkExtent3D srcExtent = {static_cast<uint32_t>(area.width), static_cast<uint32_t>(area.height),
                             1};
 
+    if (srcImage->getExtents().depth > 1)
+    {
+        // Depth > 1 means this is a 3D texture and we need special handling
+        srcOffset.z                   = layer;
+        srcSubresource.baseArrayLayer = 0;
+    }
+
     // If the source image is multisampled, we need to resolve it into a temporary image before
     // performing a readback.
     bool isMultisampled = srcImage->getSamples() > 1;
@@ -1461,10 +1475,7 @@
         ASSERT(copyAspectFlags == VK_IMAGE_ASPECT_COLOR_BIT);
 
         VkImageResolve resolveRegion                = {};
-        resolveRegion.srcSubresource.aspectMask     = copyAspectFlags;
-        resolveRegion.srcSubresource.mipLevel       = level;
-        resolveRegion.srcSubresource.baseArrayLayer = layer;
-        resolveRegion.srcSubresource.layerCount     = 1;
+        resolveRegion.srcSubresource                = srcSubresource;
         resolveRegion.srcOffset                     = srcOffset;
         resolveRegion.dstSubresource.aspectMask     = copyAspectFlags;
         resolveRegion.dstSubresource.mipLevel       = 0;
@@ -1483,6 +1494,9 @@
         level     = 0;
         layer     = 0;
         srcOffset = {0, 0, 0};
+        srcSubresource.baseArrayLayer = 0;
+        srcSubresource.layerCount     = 1;
+        srcSubresource.mipLevel       = 0;
     }
 
     VkBuffer bufferHandle      = VK_NULL_HANDLE;
@@ -1493,16 +1507,13 @@
     ANGLE_TRY(mReadPixelBuffer.allocate(contextVk, allocationSize, &readPixelBuffer, &bufferHandle,
                                         &stagingOffset, nullptr));
 
-    VkBufferImageCopy region               = {};
-    region.bufferImageHeight               = srcExtent.height;
-    region.bufferOffset                    = stagingOffset;
-    region.bufferRowLength                 = srcExtent.width;
-    region.imageExtent                     = srcExtent;
-    region.imageOffset                     = srcOffset;
-    region.imageSubresource.aspectMask     = copyAspectFlags;
-    region.imageSubresource.baseArrayLayer = layer;
-    region.imageSubresource.layerCount     = 1;
-    region.imageSubresource.mipLevel       = level;
+    VkBufferImageCopy region = {};
+    region.bufferImageHeight = srcExtent.height;
+    region.bufferOffset      = stagingOffset;
+    region.bufferRowLength   = srcExtent.width;
+    region.imageExtent       = srcExtent;
+    region.imageOffset       = srcOffset;
+    region.imageSubresource  = srcSubresource;
 
     commandBuffer->copyImageToBuffer(srcImage->getImage(), srcImage->getCurrentLayout(),
                                      bufferHandle, 1, &region);