Explicit vkImage create to wrap video frame

This uses VkImageDrmFormatModifierExplicitCreateInfoEXT instead of
VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT to
import mulit-planar external images.
More discussions about this change can be found at this Mesa issue:
https://gitlab.freedesktop.org/mesa/mesa/-/issues/6530

Bug: chromium:1258986

Change-Id: Ifde3d89e7ddf37d6a295c9d7fcc7c762f8da1e81
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/91940
Reviewed-by: Jie A Chen <jie.a.chen@intel.com>
Commit-Queue: Jie A Chen <jie.a.chen@intel.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Loko Kung <lokokung@google.com>
Reviewed-by: Austin Eng <enga@chromium.org>
diff --git a/include/dawn/native/VulkanBackend.h b/include/dawn/native/VulkanBackend.h
index 3885dad..a7957d2 100644
--- a/include/dawn/native/VulkanBackend.h
+++ b/include/dawn/native/VulkanBackend.h
@@ -17,6 +17,7 @@
 
 #include <vulkan/vulkan.h>
 
+#include <array>
 #include <vector>
 
 #include "dawn/dawn_wsi.h"
@@ -92,11 +93,20 @@
     uint32_t memoryTypeIndex;     // Must match VkMemoryAllocateInfo from image creation
 };
 
+// The plane-wise offset and stride.
+struct DAWN_NATIVE_EXPORT PlaneLayout {
+    uint64_t offset;
+    uint32_t stride;
+};
+
 // Descriptor for dma-buf file descriptor image import
 struct DAWN_NATIVE_EXPORT ExternalImageDescriptorDmaBuf : ExternalImageDescriptorFD {
     ExternalImageDescriptorDmaBuf();
+    // To be removed after chromium's switch to planeLayouts.
+    uint32_t stride = 0u;  // Stride of the buffer in bytes
 
-    uint32_t stride;       // Stride of the buffer in bytes
+    static constexpr uint32_t kMaxPlanes = 3;
+    std::array<PlaneLayout, kMaxPlanes> planeLayouts;
     uint64_t drmModifier;  // DRM modifier of the buffer
 };
 
diff --git a/src/dawn/native/vulkan/external_memory/MemoryServiceDmaBuf.cpp b/src/dawn/native/vulkan/external_memory/MemoryServiceDmaBuf.cpp
index bbbd2ca..044ef8d 100644
--- a/src/dawn/native/vulkan/external_memory/MemoryServiceDmaBuf.cpp
+++ b/src/dawn/native/vulkan/external_memory/MemoryServiceDmaBuf.cpp
@@ -311,37 +311,37 @@
     createInfoChain.Add(&externalMemoryImageCreateInfo,
                         VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO);
 
+    VkSubresourceLayout planeLayouts[ExternalImageDescriptorDmaBuf::kMaxPlanes];
+    for (uint32_t plane = 0u; plane < planeCount; ++plane) {
+        planeLayouts[plane].offset = dmaBufDescriptor->planeLayouts[plane].offset;
+        planeLayouts[plane].size = 0;  // VK_EXT_image_drm_format_modifier mandates size = 0.
+        planeLayouts[plane].rowPitch = dmaBufDescriptor->planeLayouts[plane].stride;
+        planeLayouts[plane].arrayPitch = 0;  // Not an array texture
+        planeLayouts[plane].depthPitch = 0;  // Not a depth texture
+    }
+
     // For single plane formats.
-    VkSubresourceLayout planeLayout = {};
-    planeLayout.offset = 0;
-    planeLayout.size = 0;  // VK_EXT_image_drm_format_modifier mandates size = 0.
-    planeLayout.rowPitch = dmaBufDescriptor->stride;
-    planeLayout.arrayPitch = 0;  // Not an array texture
-    planeLayout.depthPitch = 0;  // Not a depth texture
+    // To be Removed after chromium's switch to planeLayouts.
+    if (dmaBufDescriptor->stride != 0) {
+        planeLayouts[0].offset = 0;
+        planeLayouts[0].size = 0;  // VK_EXT_image_drm_format_modifier mandates size = 0.
+        planeLayouts[0].rowPitch = dmaBufDescriptor->stride;
+        planeLayouts[0].arrayPitch = 0;  // Not an array texture
+        planeLayouts[0].depthPitch = 0;  // Not a depth texture
+    }
 
     VkImageDrmFormatModifierExplicitCreateInfoEXT explicitCreateInfo = {};
     explicitCreateInfo.drmFormatModifier = dmaBufDescriptor->drmModifier;
-    explicitCreateInfo.drmFormatModifierPlaneCount = 1;
-    explicitCreateInfo.pPlaneLayouts = &planeLayout;
-
-    // For multi-planar formats, we can't explicitly specify VkSubresourceLayout for each plane
-    // due to the lack of knowledge about the required 'offset'. Alternatively
-    // VkImageDrmFormatModifierListCreateInfoEXT can be used to create image with the DRM format
-    // modifier.
-    VkImageDrmFormatModifierListCreateInfoEXT listCreateInfo = {};
-    listCreateInfo.drmFormatModifierCount = 1;
-    listCreateInfo.pDrmFormatModifiers = &dmaBufDescriptor->drmModifier;
+    explicitCreateInfo.drmFormatModifierPlaneCount = planeCount;
+    explicitCreateInfo.pPlaneLayouts = &planeLayouts[0];
 
     if (planeCount > 1) {
         // For multi-planar formats, VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT specifies that a
         // VkImageView can be plane's format which might differ from the image's format.
         createInfo.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
-        createInfoChain.Add(&listCreateInfo,
-                            VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT);
-    } else {
-        createInfoChain.Add(&explicitCreateInfo,
-                            VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT);
     }
+    createInfoChain.Add(&explicitCreateInfo,
+                        VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT);
 
     // Create a new VkImage with tiling equal to the DRM format modifier.
     VkImage image;
diff --git a/src/dawn/tests/end2end/VideoViewsTests_gbm.cpp b/src/dawn/tests/end2end/VideoViewsTests_gbm.cpp
index bc9b903..55535ce 100644
--- a/src/dawn/tests/end2end/VideoViewsTests_gbm.cpp
+++ b/src/dawn/tests/end2end/VideoViewsTests_gbm.cpp
@@ -32,6 +32,10 @@
 #define GBM_BO_USE_HW_VIDEO_DECODER (1 << 13)
 #endif
 
+#ifndef DRM_FORMAT_MOD_LINEAR
+#define DRM_FORMAT_MOD_LINEAR 0
+#endif
+
 class PlatformTextureGbm : public VideoViewsTestBackend::PlatformTexture {
   public:
     PlatformTextureGbm(wgpu::Texture&& texture, gbm_bo* gbmBo)
@@ -40,6 +44,11 @@
 
     // TODO(chromium:1258986): Add DISJOINT vkImage support for multi-plannar formats.
     bool CanWrapAsWGPUTexture() override {
+        // TODO(chromium:1258986): Figure out the failure incurred by the change to explicit vkImage
+        // create when importing.
+        if (gbm_bo_get_modifier(mGbmBo) == DRM_FORMAT_MOD_LINEAR) {
+            return false;
+        }
         ASSERT(mGbmBo != nullptr);
         // Checks if all plane handles of a multi-planar gbm_bo are same.
         gbm_bo_handle plane0Handle = gbm_bo_get_handle_for_plane(mGbmBo, 0);
@@ -174,7 +183,10 @@
         descriptor.isInitialized = true;
 
         descriptor.memoryFD = gbm_bo_get_fd(gbmBo);
-        descriptor.stride = gbm_bo_get_stride(gbmBo);
+        for (int plane = 0; plane < gbm_bo_get_plane_count(gbmBo); ++plane) {
+            descriptor.planeLayouts[plane].stride = gbm_bo_get_stride_for_plane(gbmBo, plane);
+            descriptor.planeLayouts[plane].offset = gbm_bo_get_offset(gbmBo, plane);
+        }
         descriptor.drmModifier = gbm_bo_get_modifier(gbmBo);
         descriptor.waitFDs = {};