Avoid transitions from VK_IMAGE_LAYOUT_UNDEFINED for external images

Unfortunetly, Android does not yet have a mechanism for sharing the
expected VkImageLayout when passing around AHardwareBuffer-s so
many existing users that import AHardwareBuffer-s into VkImage-s
seem to use VK_IMAGE_LAYOUT_UNDEFINED. However, the Vulkan spec's
image layout transition sections says "If the old layout is
VK_IMAGE_LAYOUT_UNDEFINED, the contents of that range may be
discarded." Some Vulkan drivers have been observed to actually
perform the discard which leads to AHardwareBuffer-s being
unintentionally cleared. See go/ahb-vkimagelayout for a more
thorough write up.

Bug: b/236179471
Test: `launch_cvd --gpu_mode=gfxstream`
Test: `launch_cvd --gpu_mode=gfxstream` with WIP ANGLE
Change-Id: Id55b5d395879012e36e529ceb512035abac77929
diff --git a/system/vulkan_enc/ResourceTracker.cpp b/system/vulkan_enc/ResourceTracker.cpp
index 63b75dd..bf700c4 100644
--- a/system/vulkan_enc/ResourceTracker.cpp
+++ b/system/vulkan_enc/ResourceTracker.cpp
@@ -7670,6 +7670,65 @@
             true /* do lock */);
     }
 
+    void on_vkCmdPipelineBarrier(
+        void* context,
+        VkCommandBuffer commandBuffer,
+        VkPipelineStageFlags srcStageMask,
+        VkPipelineStageFlags dstStageMask,
+        VkDependencyFlags dependencyFlags,
+        uint32_t memoryBarrierCount,
+        const VkMemoryBarrier* pMemoryBarriers,
+        uint32_t bufferMemoryBarrierCount,
+        const VkBufferMemoryBarrier* pBufferMemoryBarriers,
+        uint32_t imageMemoryBarrierCount,
+        const VkImageMemoryBarrier* pImageMemoryBarriers) {
+
+        VkEncoder* enc = (VkEncoder*)context;
+
+        std::vector<VkImageMemoryBarrier> updatedImageMemoryBarriers;
+        updatedImageMemoryBarriers.reserve(imageMemoryBarrierCount);
+        for (uint32_t i = 0; i < imageMemoryBarrierCount; i++) {
+            VkImageMemoryBarrier barrier = pImageMemoryBarriers[i];
+
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+            // Unfortunetly, Android does not yet have a mechanism for sharing the expected
+            // VkImageLayout when passing around AHardwareBuffer-s so many existing users
+            // that import AHardwareBuffer-s into VkImage-s/VkDeviceMemory-s simply use
+            // VK_IMAGE_LAYOUT_UNDEFINED. However, the Vulkan spec's image layout transition
+            // sections says "If the old layout is VK_IMAGE_LAYOUT_UNDEFINED, the contents of
+            // that range may be discarded." Some Vulkan drivers have been observed to actually
+            // perform the discard which leads to AHardwareBuffer-s being unintentionally
+            // cleared. See go/ahb-vkimagelayout for more information.
+            if (barrier.srcQueueFamilyIndex != barrier.dstQueueFamilyIndex &&
+                (barrier.srcQueueFamilyIndex == VK_QUEUE_FAMILY_EXTERNAL ||
+                 barrier.srcQueueFamilyIndex == VK_QUEUE_FAMILY_FOREIGN_EXT) &&
+                barrier.oldLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
+                // This is not a complete solution as the Vulkan spec does not require that
+                // Vulkan drivers perform a no-op in the case when oldLayout equals newLayout
+                // but this has been observed to be enough to work for now to avoid clearing
+                // out images.
+                // TODO(b/236179843): figure out long term solution.
+                barrier.oldLayout = barrier.newLayout;
+            }
+#endif
+
+            updatedImageMemoryBarriers.push_back(barrier);
+        }
+
+        enc->vkCmdPipelineBarrier(
+            commandBuffer,
+            srcStageMask,
+            dstStageMask,
+            dependencyFlags,
+            memoryBarrierCount,
+            pMemoryBarriers,
+            bufferMemoryBarrierCount,
+            pBufferMemoryBarriers,
+            updatedImageMemoryBarriers.size(),
+            updatedImageMemoryBarriers.data(),
+            true /* do lock */);
+    }
+
     void decDescriptorSetLayoutRef(
         void* context,
         VkDevice device,
@@ -9010,6 +9069,32 @@
         pDynamicOffsets);
 }
 
+void ResourceTracker::on_vkCmdPipelineBarrier(
+    void* context,
+    VkCommandBuffer commandBuffer,
+    VkPipelineStageFlags srcStageMask,
+    VkPipelineStageFlags dstStageMask,
+    VkDependencyFlags dependencyFlags,
+    uint32_t memoryBarrierCount,
+    const VkMemoryBarrier* pMemoryBarriers,
+    uint32_t bufferMemoryBarrierCount,
+    const VkBufferMemoryBarrier* pBufferMemoryBarriers,
+    uint32_t imageMemoryBarrierCount,
+    const VkImageMemoryBarrier* pImageMemoryBarriers) {
+    mImpl->on_vkCmdPipelineBarrier(
+        context,
+        commandBuffer,
+        srcStageMask,
+        dstStageMask,
+        dependencyFlags,
+        memoryBarrierCount,
+        pMemoryBarriers,
+        bufferMemoryBarrierCount,
+        pBufferMemoryBarriers,
+        imageMemoryBarrierCount,
+        pImageMemoryBarriers);
+}
+
 void ResourceTracker::on_vkDestroyDescriptorSetLayout(
     void* context,
     VkDevice device,