Support direct image import from buffer collections

Test: nuc:go/magma-tps#L0

Change-Id: I5a94507d9290d0af3048d32849b6a6c503d749b9
diff --git a/include/vulkan/vulkan_core.h b/include/vulkan/vulkan_core.h
index 283712d..9296d10 100644
--- a/include/vulkan/vulkan_core.h
+++ b/include/vulkan/vulkan_core.h
@@ -458,6 +458,9 @@
     VK_STRUCTURE_TYPE_IMAGEPIPE_SURFACE_CREATE_INFO_FUCHSIA = 1000214000,
     VK_STRUCTURE_TYPE_BUFFER_COLLECTION_CREATE_INFO_FUCHSIA = 1001004000,
     VK_STRUCTURE_TYPE_FUCHSIA_IMAGE_FORMAT_FUCHSIA = 1001004001,
+    VK_STRUCTURE_TYPE_IMPORT_MEMORY_BUFFER_COLLECTION_FUCHSIA = 1001004004,
+    VK_STRUCTURE_TYPE_BUFFER_COLLECTION_IMAGE_CREATE_INFO_FUCHSIA = 1001004005,
+    VK_STRUCTURE_TYPE_BUFFER_COLLECTION_PROPERTIES_FUCHSIA = 1001004006,
     VK_STRUCTURE_TYPE_IMPORT_MEMORY_FUCHSIA_HANDLE_INFO_KHR = 1001000000,
     VK_STRUCTURE_TYPE_MEMORY_FUCHSIA_HANDLE_PROPERTIES_KHR = 1001000001,
     VK_STRUCTURE_TYPE_MEMORY_GET_FUCHSIA_HANDLE_INFO_KHR = 1001000002,
diff --git a/include/vulkan/vulkan_fuchsia.h b/include/vulkan/vulkan_fuchsia.h
index 1977f5c..ab7d636 100644
--- a/include/vulkan/vulkan_fuchsia.h
+++ b/include/vulkan/vulkan_fuchsia.h
@@ -150,10 +150,33 @@
     uint32_t           imageFormatSize;
 } VkFuchsiaImageFormatFUCHSIA;
 
+typedef struct VkImportMemoryBufferCollectionFUCHSIA {
+    VkStructureType              sType;
+    const void*                  pNext;
+    VkBufferCollectionFUCHSIA    collection;
+    uint32_t                     index;
+} VkImportMemoryBufferCollectionFUCHSIA;
+
+typedef struct VkBufferCollectionImageCreateInfoFUCHSIA {
+    VkStructureType              sType;
+    const void*                  pNext;
+    VkBufferCollectionFUCHSIA    collection;
+    uint32_t                     index;
+} VkBufferCollectionImageCreateInfoFUCHSIA;
+
+typedef struct VkBufferCollectionPropertiesFUCHSIA {
+    VkStructureType    sType;
+    void*              pNext;
+    uint32_t           memoryTypeBits;
+    uint32_t           count;
+} VkBufferCollectionPropertiesFUCHSIA;
+
 
 typedef VkResult (VKAPI_PTR *PFN_vkCreateBufferCollectionFUCHSIA)(VkDevice device, const VkBufferCollectionCreateInfoFUCHSIA* pImportInfo, const VkAllocationCallbacks* pAllocator, VkBufferCollectionFUCHSIA* pCollection);
 typedef VkResult (VKAPI_PTR *PFN_vkSetBufferCollectionConstraintsFUCHSIA)(VkDevice device, VkBufferCollectionFUCHSIA collection, const VkImageCreateInfo* pImageInfo);
 typedef void (VKAPI_PTR *PFN_vkDestroyBufferCollectionFUCHSIA)(VkDevice device, VkBufferCollectionFUCHSIA collection, const VkAllocationCallbacks* pAllocator);
+typedef VkResult (VKAPI_PTR *PFN_vkGetBufferCollectionPropertiesFUCHSIA)(VkDevice device, VkBufferCollectionFUCHSIA collection, VkBufferCollectionPropertiesFUCHSIA* pProperties);
+
 
 #ifndef VK_NO_PROTOTYPES
 VKAPI_ATTR VkResult VKAPI_CALL vkCreateBufferCollectionFUCHSIA(
@@ -171,6 +194,11 @@
     VkDevice                                    device,
     VkBufferCollectionFUCHSIA                   collection,
     const VkAllocationCallbacks*                pAllocator);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetBufferCollectionPropertiesFUCHSIA(
+    VkDevice                                    device,
+    VkBufferCollectionFUCHSIA                   collection,
+    VkBufferCollectionPropertiesFUCHSIA*        pProperties);
 #endif
 
 
@@ -254,4 +282,4 @@
 }
 #endif
 
-#endif
\ No newline at end of file
+#endif
diff --git a/src/intel/vulkan/anv_device.c b/src/intel/vulkan/anv_device.c
index 86bd022..83e82c4 100644
--- a/src/intel/vulkan/anv_device.c
+++ b/src/intel/vulkan/anv_device.c
@@ -2220,6 +2220,8 @@
       vk_find_struct_const(pAllocateInfo->pNext, IMPORT_MEMORY_FUCHSIA_HANDLE_INFO_KHR);
    const VkImportMemoryZirconHandleInfoFUCHSIA *fuchsia_info =
       vk_find_struct_const(pAllocateInfo->pNext, TEMP_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA);
+   const VkImportMemoryBufferCollectionFUCHSIA* fuchsia_buffer_collection =
+       vk_find_struct_const(pAllocateInfo->pNext, IMPORT_MEMORY_BUFFER_COLLECTION_FUCHSIA);
 #endif // VK_USE_PLATFORM_FUCHSIA
 
    /* The Vulkan spec permits handleType to be 0, in which case the struct is
@@ -2338,6 +2340,42 @@
       if (result != VK_SUCCESS)
          goto fail;
 
+   } else if (fuchsia_buffer_collection) {
+      VkDeviceSize aligned_alloc_size = align_u64(pAllocateInfo->allocationSize, 4096);
+
+      uint32_t handle;
+      uint32_t offset;
+      VkResult result =
+          anv_get_buffer_collection_handle(device, fuchsia_buffer_collection->collection,
+                                           fuchsia_buffer_collection->index, &handle, &offset);
+      if (result != VK_SUCCESS)
+         goto fail;
+
+      // The anv_buffer_handle_t isn't a unique handle per object, so the cache
+      // lookup in the import will always fail.
+      // TODO(MA-320) - get a unique id for this object and use that as the cache key;
+      // then clients will be able to import a buffer more than once.
+      anv_buffer_handle_t buffer;
+      uint64_t import_size;
+      int status = anv_gem_import_fuchsia_buffer(device, handle, &buffer, &import_size);
+      if (status != 0)
+         return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR);
+      if (import_size < aligned_alloc_size) {
+         result = vk_errorf(device->instance, device, VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR,
+                            "aligned allocationSize too large for "
+                            "VK_EXTERNAL_MEMORY_HANDLE_TYPE_FUCHSIA_BIT_KHR: "
+                            "%" PRIu64 "B > %" PRIu64 "B",
+                            aligned_alloc_size, import_size);
+         anv_gem_close(device, buffer);
+         goto fail;
+      }
+
+      result = anv_bo_cache_import_buffer_handle(device, &device->bo_cache, buffer,
+                                                 bo_flags | ANV_BO_EXTERNAL, aligned_alloc_size,
+                                                 &mem->bo);
+      if (result != VK_SUCCESS)
+         goto fail;
+
 #endif // VK_USE_PLATFORM_FUCHSIA
 
    } else {
diff --git a/src/intel/vulkan/anv_image.c b/src/intel/vulkan/anv_image.c
index dfb976c..9554495 100644
--- a/src/intel/vulkan/anv_image.c
+++ b/src/intel/vulkan/anv_image.c
@@ -645,15 +645,24 @@
 #if VK_USE_PLATFORM_FUCHSIA
    const struct VkFuchsiaImageFormatFUCHSIA *image_format_fuchsia =
       vk_find_struct_const(pCreateInfo->pNext, FUCHSIA_IMAGE_FORMAT_FUCHSIA);
-   if (image_format_fuchsia) {
+   const struct VkBufferCollectionImageCreateInfoFUCHSIA* buffer_collection_fuchsia =
+       vk_find_struct_const(pCreateInfo->pNext, BUFFER_COLLECTION_IMAGE_CREATE_INFO_FUCHSIA);
+   if (image_format_fuchsia || buffer_collection_fuchsia) {
       const int kParamCount = 4;
       struct anv_fuchsia_image_plane_params params[kParamCount];
       isl_tiling_flags_t tiling_flags;
       bool non_cache_coherent;
-      VkResult result = anv_image_params_from_fuchsia_image(device, pCreateInfo, params,
-                                                            &tiling_flags, &non_cache_coherent);
+      VkResult result;
+      if (image_format_fuchsia) {
+         result = anv_image_params_from_fuchsia_image(device, pCreateInfo, params, &tiling_flags,
+                                                      &non_cache_coherent);
+      } else {
+         result =
+             anv_image_params_from_buffer_collection(device, buffer_collection_fuchsia->collection,
+                                                     params, &tiling_flags, &non_cache_coherent);
+      }
       if (result != VK_SUCCESS)
-          return result;
+         return result;
 
       // We support only one bytes_per_row for all planes.
       uint32_t bytes_per_row = params[0].bytes_per_row;
diff --git a/src/intel/vulkan/anv_magma_buffer_collection.c b/src/intel/vulkan/anv_magma_buffer_collection.c
index b1c7ea1..1c1bf75 100644
--- a/src/intel/vulkan/anv_magma_buffer_collection.c
+++ b/src/intel/vulkan/anv_magma_buffer_collection.c
@@ -255,30 +255,46 @@
    return VK_SUCCESS;
 }
 
-VkResult anv_image_params_from_fuchsia_image(
-    VkDevice vk_device, const VkImageCreateInfo* pCreateInfo,
+VkResult anv_GetBufferCollectionPropertiesFUCHSIA(VkDevice vk_device,
+                                                  VkBufferCollectionFUCHSIA vk_collection,
+                                                  VkBufferCollectionPropertiesFUCHSIA* pProperties)
+{
+   ANV_FROM_HANDLE(anv_device, device, vk_device);
+   ANV_FROM_HANDLE(anv_buffer_collection, buffer_collection, vk_collection);
+
+   magma_sysmem_connection_t sysmem_connection;
+   magma_status_t status = AnvMagmaGetSysmemConnection(device->connection, &sysmem_connection);
+   if (status != MAGMA_STATUS_OK)
+      return ANV_MAGMA_DRET(VK_ERROR_DEVICE_LOST);
+   magma_buffer_format_description_t description;
+   status = magma_sysmem_get_description_from_collection(
+       sysmem_connection, buffer_collection->buffer_collection, &description);
+   if (status != MAGMA_STATUS_OK)
+      return ANV_MAGMA_DRET(VK_ERROR_DEVICE_LOST);
+
+   status = magma_get_buffer_count(description, &pProperties->count);
+   magma_buffer_format_description_release(description);
+
+   if (status != MAGMA_STATUS_OK)
+      return ANV_MAGMA_DRET(VK_ERROR_DEVICE_LOST);
+
+   struct anv_physical_device* pdevice = &device->instance->physicalDevice;
+   // All memory types supported.
+   pProperties->memoryTypeBits = (1ull << pdevice->memory.type_count) - 1;
+   return VK_SUCCESS;
+}
+
+// Takes ownership of the buffer format description.
+static VkResult anv_image_params_from_description(
+    magma_buffer_format_description_t description,
     struct anv_fuchsia_image_plane_params params_out[MAGMA_MAX_IMAGE_PLANES],
     isl_tiling_flags_t* tiling_flags_out, bool* not_cache_coherent_out)
 {
-   assert(pCreateInfo->arrayLayers == 1);
-   assert(pCreateInfo->extent.depth == 1);
-
-   const struct VkFuchsiaImageFormatFUCHSIA* image_format_fuchsia =
-       vk_find_struct_const(pCreateInfo->pNext, FUCHSIA_IMAGE_FORMAT_FUCHSIA);
-   assert(image_format_fuchsia);
-
-   magma_buffer_format_description_t description;
-   magma_status_t status;
-   status = magma_get_buffer_format_description(
-       image_format_fuchsia->imageFormat, image_format_fuchsia->imageFormatSize, &description);
-   if (status != MAGMA_STATUS_OK)
-      return ANV_MAGMA_DRET(VK_ERROR_FORMAT_NOT_SUPPORTED);
-
    magma_bool_t has_format_modifier;
    uint64_t format_modifier;
    magma_image_plane_t planes[MAGMA_MAX_IMAGE_PLANES];
 
-   status = magma_get_buffer_format_plane_info(description, planes);
+   magma_status_t status = magma_get_buffer_format_plane_info(description, planes);
    if (status == MAGMA_STATUS_OK) {
       status =
           magma_get_buffer_format_modifier(description, &has_format_modifier, &format_modifier);
@@ -321,4 +337,67 @@
    return VK_SUCCESS;
 }
 
+VkResult anv_image_params_from_fuchsia_image(
+    VkDevice vk_device, const VkImageCreateInfo* pCreateInfo,
+    struct anv_fuchsia_image_plane_params params_out[MAGMA_MAX_IMAGE_PLANES],
+    isl_tiling_flags_t* tiling_flags_out, bool* not_cache_coherent_out)
+{
+   assert(pCreateInfo->arrayLayers == 1);
+   assert(pCreateInfo->extent.depth == 1);
+
+   const struct VkFuchsiaImageFormatFUCHSIA* image_format_fuchsia =
+       vk_find_struct_const(pCreateInfo->pNext, FUCHSIA_IMAGE_FORMAT_FUCHSIA);
+   assert(image_format_fuchsia);
+
+   magma_buffer_format_description_t description;
+   magma_status_t status;
+   status = magma_get_buffer_format_description(
+       image_format_fuchsia->imageFormat, image_format_fuchsia->imageFormatSize, &description);
+   if (status != MAGMA_STATUS_OK)
+      return ANV_MAGMA_DRET(VK_ERROR_FORMAT_NOT_SUPPORTED);
+
+   return anv_image_params_from_description(description, params_out, tiling_flags_out,
+                                            not_cache_coherent_out);
+}
+
+VkResult anv_image_params_from_buffer_collection(
+    VkDevice vk_device, VkBufferCollectionFUCHSIA vk_collection,
+    struct anv_fuchsia_image_plane_params params_out[MAGMA_MAX_IMAGE_PLANES],
+    isl_tiling_flags_t* tiling_flags_out, bool* not_cache_coherent_out)
+{
+   ANV_FROM_HANDLE(anv_device, device, vk_device);
+   ANV_FROM_HANDLE(anv_buffer_collection, buffer_collection, vk_collection);
+
+   magma_sysmem_connection_t sysmem_connection;
+   magma_status_t status = AnvMagmaGetSysmemConnection(device->connection, &sysmem_connection);
+   if (status != MAGMA_STATUS_OK)
+      return ANV_MAGMA_DRET(VK_ERROR_DEVICE_LOST);
+   magma_buffer_format_description_t description;
+   status = magma_sysmem_get_description_from_collection(
+       sysmem_connection, buffer_collection->buffer_collection, &description);
+   if (status != MAGMA_STATUS_OK)
+      return ANV_MAGMA_DRET(VK_ERROR_DEVICE_LOST);
+
+   return anv_image_params_from_description(description, params_out, tiling_flags_out,
+                                            not_cache_coherent_out);
+}
+
+VkResult anv_get_buffer_collection_handle(struct anv_device* device,
+                                          VkBufferCollectionFUCHSIA vk_collection, uint32_t index,
+                                          uint32_t* handle_out, uint32_t* offset_out)
+{
+   ANV_FROM_HANDLE(anv_buffer_collection, buffer_collection, vk_collection);
+
+   magma_sysmem_connection_t sysmem_connection;
+   magma_status_t status = AnvMagmaGetSysmemConnection(device->connection, &sysmem_connection);
+   if (status != MAGMA_STATUS_OK)
+      return ANV_MAGMA_DRET(VK_ERROR_DEVICE_LOST);
+   if (magma_sysmem_get_buffer_handle_from_collection(sysmem_connection,
+                                                      buffer_collection->buffer_collection, index,
+                                                      handle_out, offset_out) != MAGMA_STATUS_OK) {
+      return ANV_MAGMA_DRET(VK_ERROR_DEVICE_LOST);
+   }
+   return VK_SUCCESS;
+}
+
 #endif // VK_USE_PLATFORM_FUCHSIA
diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h
index 3fe8ae5..fce08c4 100644
--- a/src/intel/vulkan/anv_private.h
+++ b/src/intel/vulkan/anv_private.h
@@ -3331,6 +3331,16 @@
                                              isl_tiling_flags_t* tiling_flags_out,
                                              bool* not_cache_coherent_out);
 
+VkResult
+anv_image_params_from_buffer_collection(VkDevice device, VkBufferCollectionFUCHSIA vk_collection,
+                                        struct anv_fuchsia_image_plane_params params_out[4],
+                                        isl_tiling_flags_t* tiling_flags_out,
+                                        bool* not_cache_coherent_out);
+
+VkResult anv_get_buffer_collection_handle(struct anv_device* device,
+                                          VkBufferCollectionFUCHSIA collection, uint32_t index,
+                                          uint32_t* handle_out, uint32_t* offset_out);
+
 #endif
 
 #define ANV_DEFINE_HANDLE_CASTS(__anv_type, __VkType)                      \
diff --git a/src/vulkan/registry/vk.xml b/src/vulkan/registry/vk.xml
index 887f696..35e793b 100644
--- a/src/vulkan/registry/vk.xml
+++ b/src/vulkan/registry/vk.xml
@@ -2166,11 +2166,29 @@
             <member>const <type>void</type>*                      <name>imageFormat</name></member>
             <member><type>uint32_t</type>                         <name>imageFormatSize</name></member>
         </type>
+        <type category="struct" name="VkImportMemoryBufferCollectionFUCHSIA" structextends="VkMemoryAllocateInfo">
+            <member values="VK_STRUCTURE_TYPE_IMPORT_MEMORY_BUFFER_COLLECTION_FUCHSIA"><type>VkStructureType</type> <name>sType</name></member>
+            <member>const <type>void</type>*                      <name>pNext</name></member>
+            <member><type>VkBufferCollectionFUCHSIA</type>        <name>collection</name></member>
+            <member><type>uint32_t</type>                         <name>index</name></member>
+        </type>
+        <type category="struct" name="VkBufferCollectionImageCreateInfoFUCHSIA" structextends="VkImageCreateInfo">
+            <member values="VK_STRUCTURE_TYPE_BUFFER_COLLECTION_IMAGE_CREATE_INFO_FUCHSIA"><type>VkStructureType</type> <name>sType</name></member>
+            <member>const <type>void</type>*                      <name>pNext</name></member>
+            <member><type>VkBufferCollectionFUCHSIA</type>        <name>collection</name></member>
+            <member><type>uint32_t</type>                         <name>index</name></member>
+        </type>
         <type category="struct" name="VkBufferCollectionCreateInfoFUCHSIA">
             <member values="VK_STRUCTURE_TYPE_BUFFER_COLLECTION_CREATE_INFO_FUCHSIA"><type>VkStructureType</type> <name>sType</name></member>
             <member>const <type>void</type>*                      <name>pNext</name></member>
             <member><type>zx_handle_t</type>                      <name>collectionToken</name></member>
         </type>
+        <type category="struct" name="VkBufferCollectionPropertiesFUCHSIA">
+            <member values="VK_STRUCTURE_TYPE_BUFFER_COLLECTION_PROPERTIES_FUCHSIA"><type>VkStructureType</type> <name>sType</name></member>
+            <member><type>void</type>*                            <name>pNext</name></member>
+            <member><type>uint32_t</type>                         <name>memoryTypeBits</name></member>
+            <member><type>uint32_t</type>                         <name>count</name></member>
+        </type>
         <type category="struct" name="VkWin32KeyedMutexAcquireReleaseInfoKHR" structextends="VkSubmitInfo">
             <member values="VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
             <member>const <type>void</type>*                      <name>pNext</name></member>
@@ -5999,6 +6017,12 @@
             <param><type>VkBufferCollectionFUCHSIA</type> <name>collection</name></param>
             <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
         </command>
+        <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+            <proto><type>VkResult</type> <name>vkGetBufferCollectionPropertiesFUCHSIA</name></proto>
+            <param><type>VkDevice</type> <name>device</name></param>
+            <param><type>VkBufferCollectionFUCHSIA</type> <name>collection</name></param>
+            <param><type>VkBufferCollectionPropertiesFUCHSIA</type>* <name>pProperties</name></param>
+        </command>
         <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY">
             <proto><type>VkResult</type> <name>vkCreateDebugReportCallbackEXT</name></proto>
             <param><type>VkInstance</type> <name>instance</name></param>
@@ -10290,12 +10314,19 @@
                 <enum offset="1" extends="VkStructureType"              name="VK_STRUCTURE_TYPE_FUCHSIA_IMAGE_FORMAT_FUCHSIA"/>
                 <enum offset="2" extends="VkObjectType"                 name="VK_OBJECT_TYPE_BUFFER_COLLECTION_FUCHSIA" comment="VkBufferCollectionFUCHSIA"/>
                 <enum offset="3" extends="VkDebugReportObjectTypeEXT"   name="VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_COLLECTION_FUCHSIA_EXT"/>
+                <enum offset="4" extends="VkStructureType"              name="VK_STRUCTURE_TYPE_IMPORT_MEMORY_BUFFER_COLLECTION_FUCHSIA"/>
+                <enum offset="5" extends="VkStructureType"              name="VK_STRUCTURE_TYPE_BUFFER_COLLECTION_IMAGE_CREATE_INFO_FUCHSIA"/>
+                <enum offset="6" extends="VkStructureType"              name="VK_STRUCTURE_TYPE_BUFFER_COLLECTION_PROPERTIES_FUCHSIA"/>
                 <type name="VkBufferCollectionFUCHSIA"/>
                 <type name="VkBufferCollectionCreateInfoFUCHSIA"/>
                 <type name="VkFuchsiaImageFormatFUCHSIA"/>
+                <type name="VkImportMemoryBufferCollectionFUCHSIA"/>
+                <type name="VkBufferCollectionImageCreateInfoFUCHSIA"/>
+                <type name="VkBufferCollectionPropertiesFUCHSIA"/>
                 <command name="vkCreateBufferCollectionFUCHSIA"/>
                 <command name="vkSetBufferCollectionConstraintsFUCHSIA"/>
                 <command name="vkDestroyBufferCollectionFUCHSIA"/>
+                <command name="vkGetBufferCollectionPropertiesFUCHSIA"/>
             </require>
         </extension>
         <extension name="VK_FUCHSIA_external_memory" number="1006" type="device" requires="VK_KHR_external_memory_capabilities,VK_KHR_external_memory" author="FUCHSIA" contact="Craig Stout @cdotstout" supported="vulkan" platform="fuchsia">