gfxstream: Add linearPeerImage for Linux guests, to use for imageLayout queries

BUG=343234676
TEST=gfxstream guest Linux

Change-Id: I9190b73aa16adecf7fe4cee0715b2278631b3703
diff --git a/guest/vulkan_enc/ResourceTracker.cpp b/guest/vulkan_enc/ResourceTracker.cpp
index 948c316..f8b818e 100644
--- a/guest/vulkan_enc/ResourceTracker.cpp
+++ b/guest/vulkan_enc/ResourceTracker.cpp
@@ -3780,9 +3780,8 @@
                     .arrayLayer = 0,
                 };
                 VkSubresourceLayout subResourceLayout;
-                enc->vkGetImageSubresourceLayout(device, dedicatedAllocInfoPtr->image,
-                                                 &imageSubresource, &subResourceLayout,
-                                                 true /* do lock */);
+                on_vkGetImageSubresourceLayout(context, device, dedicatedAllocInfoPtr->image,
+                                               &imageSubresource, &subResourceLayout);
                 if (!subResourceLayout.rowPitch) {
                     mesa_loge("%s: Failed to query stride for VirtGpu resource creation.");
                     return VK_ERROR_INITIALIZATION_FAILED;
@@ -4311,6 +4310,34 @@
     info.isDmaBufImage = isDmaBufImage;
     if (info.isDmaBufImage) {
         updateMemoryTypeBits(&memReqs.memoryTypeBits, mCaps.vulkanCapset.colorBufferMemoryIndex);
+        if (localCreateInfo.tiling == VK_IMAGE_TILING_OPTIMAL) {
+            // Linux WSI calls vkGetImageSubresourceLayout() to query the stride for swapchain
+            // support. Similarly, stride is also queried from vkGetImageSubresourceLayout() to
+            // determine the stride for colorBuffer resource creation (guest-side dmabuf resource).
+            // To satisfy valid usage of this API, must call on the linearPeerImage for the VkImage
+            // in question. As long as these two use cases match, the rowPitch won't actually be
+            // used by WSI.
+            VkImageCreateInfo linearPeerImageCreateInfo = {
+                .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
+                .pNext = nullptr,
+                .flags = {},
+                .imageType = VK_IMAGE_TYPE_2D,
+                .format = localCreateInfo.format,
+                .extent = localCreateInfo.extent,
+                .mipLevels = 1,
+                .arrayLayers = 1,
+                .samples = VK_SAMPLE_COUNT_1_BIT,
+                .tiling = VK_IMAGE_TILING_LINEAR,
+                .usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
+                .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
+                .queueFamilyIndexCount = 0,
+                .pQueueFamilyIndices = nullptr,
+                .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
+            };
+            res = enc->vkCreateImage(device, &linearPeerImageCreateInfo, pAllocator,
+                                     &info.linearPeerImage, true /* do lock */);
+            if (res != VK_SUCCESS) return res;
+        }
     }
 #endif
 
@@ -5093,6 +5120,15 @@
     }
 #endif
     VkEncoder* enc = (VkEncoder*)context;
+#if defined(LINUX_GUEST_BUILD)
+    auto imageInfoIt = info_VkImage.find(image);
+    if (imageInfoIt != info_VkImage.end()) {
+        auto& imageInfo = imageInfoIt->second;
+        if (imageInfo.linearPeerImage) {
+            enc->vkDestroyImage(device, imageInfo.linearPeerImage, pAllocator, true /* do lock */);
+        }
+    }
+#endif
     enc->vkDestroyImage(device, image, pAllocator, true /* do lock */);
 }
 
@@ -5140,6 +5176,23 @@
     transformImageMemoryRequirements2ForGuest(pInfo->image, pMemoryRequirements);
 }
 
+void ResourceTracker::on_vkGetImageSubresourceLayout(void* context, VkDevice device, VkImage image,
+                                                     const VkImageSubresource* pSubresource,
+                                                     VkSubresourceLayout* pLayout) {
+    VkEncoder* enc = (VkEncoder*)context;
+    VkImage targetImage = image;
+#if defined(LINUX_GUEST_BUILD)
+    auto it = info_VkImage.find(image);
+    if (it == info_VkImage.end()) return;
+    const auto& info = it->second;
+    if (info.linearPeerImage) {
+        targetImage = info.linearPeerImage;
+    }
+#endif
+    enc->vkGetImageSubresourceLayout(device, targetImage, pSubresource, pLayout,
+                                     true /* do lock */);
+}
+
 VkResult ResourceTracker::on_vkBindImageMemory(void* context, VkResult, VkDevice device,
                                                VkImage image, VkDeviceMemory memory,
                                                VkDeviceSize memoryOffset) {