vkr: implement dma_buf fd import and properties query

Translate the below:
VkImportMemoryResourceInfoMESA -> VkImportMemoryFdInfoKHR
vkGetMemoryResourcePropertiesMESA -> vkGetMemoryFdPropertiesKHR

Signed-off-by: Yiwei Zhang <zzyiwei@chromium.org>
Reviewed-by: Chia-I Wu <olvaffe@gmail.com>
diff --git a/src/vkr_renderer.c b/src/vkr_renderer.c
index a7bb18a..1797c79 100644
--- a/src/vkr_renderer.c
+++ b/src/vkr_renderer.c
@@ -145,6 +145,8 @@
 
    PFN_vkGetImageDrmFormatModifierPropertiesEXT get_image_drm_format_modifier_properties;
 
+   PFN_vkGetMemoryFdPropertiesKHR get_memory_fd_properties;
+
    struct list_head queues;
 
    struct list_head free_syncs;
@@ -1508,6 +1510,9 @@
    dev->get_image_drm_format_modifier_properties = (PFN_vkGetImageDrmFormatModifierPropertiesEXT)
       vkGetDeviceProcAddr(handle, "vkGetImageDrmFormatModifierPropertiesEXT");
 
+   dev->get_memory_fd_properties = (PFN_vkGetMemoryFdPropertiesKHR)
+      vkGetDeviceProcAddr(handle, "vkGetMemoryFdPropertiesKHR");
+
    list_inithead(&dev->queues);
    list_inithead(&dev->free_syncs);
 
@@ -1628,6 +1633,30 @@
    vkr_cs_decoder_set_fatal(&ctx->decoder);
 }
 
+static bool
+vkr_get_fd_handle_type_from_virgl_fd_type(struct vkr_physical_device *dev, enum virgl_resource_fd_type fd_type, VkExternalMemoryHandleTypeFlagBits *out_handle_type)
+{
+    assert(dev);
+    assert(out_handle_type);
+
+    switch (fd_type) {
+    case VIRGL_RESOURCE_FD_DMABUF:
+       if (!dev->EXT_external_memory_dma_buf)
+          return false;
+       *out_handle_type = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
+       break;
+    case VIRGL_RESOURCE_FD_OPAQUE:
+       if (!dev->KHR_external_memory_fd)
+          return false;
+       *out_handle_type = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
+       break;
+    default:
+       return false;
+    }
+
+    return true;
+}
+
 static void
 vkr_dispatch_vkAllocateMemory(struct vn_dispatch_context *dispatch, struct vn_command_vkAllocateMemory *args)
 {
@@ -1649,8 +1678,42 @@
       ((VkMemoryAllocateInfo *)args->pAllocateInfo)->pNext = &export_info;
 #endif
 
+   /* translate VkImportMemoryResourceInfoMESA into VkImportMemoryFdInfoKHR */
+   VkImportMemoryResourceInfoMESA *import_resource_info = NULL;
+   VkImportMemoryFdInfoKHR import_fd_info = {
+      .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
+      .fd = -1,
+   };
+   VkBaseInStructure *pprev = (VkBaseInStructure *)args->pAllocateInfo;
+   while (pprev->pNext) {
+      if (pprev->pNext->sType == VK_STRUCTURE_TYPE_IMPORT_MEMORY_RESOURCE_INFO_MESA) {
+          import_resource_info = (VkImportMemoryResourceInfoMESA *)pprev->pNext;
+          import_fd_info.pNext = pprev->pNext->pNext;
+          pprev->pNext = (const struct VkBaseInStructure *)&import_fd_info;
+          break;
+      }
+      pprev = (VkBaseInStructure *)pprev->pNext;
+   }
+   if (import_resource_info) {
+      uint32_t res_id = import_resource_info->resourceId;
+      struct vkr_resource_attachment *att = util_hash_table_get(ctx->resource_table, uintptr_to_pointer(res_id));
+      if (!att || !att->resource) {
+         args->ret = VK_ERROR_INVALID_EXTERNAL_HANDLE;
+         return;
+      }
+
+      enum virgl_resource_fd_type fd_type = virgl_resource_export_fd(att->resource, &import_fd_info.fd);
+      if (!vkr_get_fd_handle_type_from_virgl_fd_type(dev->physical_device, fd_type, &import_fd_info.handleType)) {
+         close(import_fd_info.fd);
+         args->ret = VK_ERROR_INVALID_EXTERNAL_HANDLE;
+         return;
+      }
+   }
+
    struct vkr_device_memory *mem = calloc(1, sizeof(*mem));
    if (!mem) {
+      if (import_resource_info)
+         close(import_fd_info.fd);
       args->ret = VK_ERROR_OUT_OF_HOST_MEMORY;
       return;
    }
@@ -1661,6 +1724,8 @@
    vn_replace_vkAllocateMemory_args_handle(args);
    args->ret = vkAllocateMemory(args->device, args->pAllocateInfo, NULL, &mem->base.handle.device_memory);
    if (args->ret != VK_SUCCESS) {
+      if (import_resource_info)
+         close(import_fd_info.fd);
       free(mem);
       return;
    }
@@ -3225,6 +3290,38 @@
 }
 
 static void
+vkr_dispatch_vkGetMemoryResourcePropertiesMESA(struct vn_dispatch_context *dispatch, struct vn_command_vkGetMemoryResourcePropertiesMESA *args)
+{
+   struct vkr_context *ctx = dispatch->data;
+   struct vkr_device *dev = (struct vkr_device *)args->device;
+   if (!dev || dev->base.type != VK_OBJECT_TYPE_DEVICE) {
+      vkr_cs_decoder_set_fatal(&ctx->decoder);
+      return;
+   }
+
+   struct vkr_resource_attachment *att = util_hash_table_get(ctx->resource_table, uintptr_to_pointer(args->resourceId));
+   if (!att || !att->resource) {
+      args->ret = VK_ERROR_INVALID_EXTERNAL_HANDLE;
+      return;
+   }
+
+   VkExternalMemoryHandleTypeFlagBits handle_type;
+   if (!vkr_get_fd_handle_type_from_virgl_fd_type(dev->physical_device, att->resource->fd_type, &handle_type)) {
+      args->ret = VK_ERROR_INVALID_EXTERNAL_HANDLE;
+      return;
+   }
+
+   VkMemoryFdPropertiesKHR memory_fd_properties = {
+      .sType = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR,
+      .pNext = NULL,
+      .memoryTypeBits = 0,
+   };
+   vn_replace_vkGetMemoryResourcePropertiesMESA_args_handle(args);
+   args->ret = dev->get_memory_fd_properties(args->device, handle_type, att->resource->fd, &memory_fd_properties);
+   args->pMemoryResourceProperties->memoryTypeBits = memory_fd_properties.memoryTypeBits;
+}
+
+static void
 vkr_dispatch_debug_log(UNUSED struct vn_dispatch_context *dispatch, const char *msg)
 {
    vrend_printf("vkr: %s\n", msg);
@@ -3464,6 +3561,8 @@
    dispatch->dispatch_vkCmdDrawIndirectByteCountEXT = vkr_dispatch_vkCmdDrawIndirectByteCountEXT;
 
    dispatch->dispatch_vkGetImageDrmFormatModifierPropertiesEXT = vkr_dispatch_vkGetImageDrmFormatModifierPropertiesEXT;
+
+   dispatch->dispatch_vkGetMemoryResourcePropertiesMESA = vkr_dispatch_vkGetMemoryResourcePropertiesMESA;
 }
 
 static int