Mesa (main): venus: implement AHB allocation and import (part 2/2)

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Wed May 26 20:34:41 UTC 2021


Module: Mesa
Branch: main
Commit: 7370f339531e48bb1973cf64f75b33d6be90835b
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=7370f339531e48bb1973cf64f75b33d6be90835b

Author: Yiwei Zhang <zzyiwei at chromium.org>
Date:   Wed May 19 04:42:57 2021 +0000

venus: implement AHB allocation and import (part 2/2)

TODO left to fix plane count > 1 case for external memory.

Signed-off-by: Yiwei Zhang <zzyiwei at chromium.org>
Reviewed-by: Chia-I Wu <olvaffe at gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/10960>

---

 src/virtio/vulkan/vn_android.c       | 175 +++++++++++++++++++++++++++++++++--
 src/virtio/vulkan/vn_android.h       |   9 ++
 src/virtio/vulkan/vn_device_memory.c |   3 +
 src/virtio/vulkan/vn_device_memory.h |   3 +
 4 files changed, 184 insertions(+), 6 deletions(-)

diff --git a/src/virtio/vulkan/vn_android.c b/src/virtio/vulkan/vn_android.c
index e3a07fd43d2..2c780942e65 100644
--- a/src/virtio/vulkan/vn_android.c
+++ b/src/virtio/vulkan/vn_android.c
@@ -21,6 +21,7 @@
 #include "util/os_file.h"
 
 #include "vn_device.h"
+#include "vn_device_memory.h"
 #include "vn_image.h"
 #include "vn_queue.h"
 
@@ -240,10 +241,14 @@ static VkResult
 vn_android_get_dma_buf_from_native_handle(const native_handle_t *handle,
                                           int *out_dma_buf)
 {
-   /* TODO support multi-planar format */
-   if (handle->numFds != 1) {
-      if (VN_DEBUG(WSI))
-         vn_log(NULL, "handle->numFds is %d, expected 1", handle->numFds);
+   /* There can be multiple fds wrapped inside a native_handle_t, but we
+    * expect only the 1st one points to the dma_buf. For multi-planar format,
+    * there should only exist one dma_buf as well. The other fd(s) may point
+    * to shared memory used to store buffer metadata or other vendor specific
+    * bits.
+    */
+   if (handle->numFds < 1) {
+      vn_log(NULL, "handle->numFds is %d, expected >= 1", handle->numFds);
       return VK_ERROR_INVALID_EXTERNAL_HANDLE;
    }
 
@@ -979,7 +984,116 @@ vn_android_device_import_ahb(struct vn_device *dev,
                              const VkMemoryAllocateInfo *alloc_info,
                              struct AHardwareBuffer *ahb)
 {
-   return VK_ERROR_OUT_OF_HOST_MEMORY;
+   const VkMemoryDedicatedAllocateInfo *dedicated_info =
+      vk_find_struct_const(alloc_info->pNext, MEMORY_DEDICATED_ALLOCATE_INFO);
+   const native_handle_t *handle = NULL;
+   int dma_buf_fd = -1;
+   int dup_fd = -1;
+   VkDeviceSize alloc_size = alloc_info->allocationSize;
+   VkResult result = VK_SUCCESS;
+
+   handle = AHardwareBuffer_getNativeHandle(ahb);
+   result = vn_android_get_dma_buf_from_native_handle(handle, &dma_buf_fd);
+   if (result != VK_SUCCESS)
+      return result;
+
+   /* If ahb is for an image, finish the deferred image creation first */
+   if (dedicated_info && dedicated_info->image != VK_NULL_HANDLE) {
+      const VkAllocationCallbacks *alloc = &dev->base.base.alloc;
+      struct vn_image *img = vn_image_from_handle(dedicated_info->image);
+      VkImageCreateInfo *image_info = &img->deferred_info->create;
+      uint32_t strides[4] = { 0, 0, 0, 0 };
+      uint32_t offsets[4] = { 0, 0, 0, 0 };
+      uint64_t format_modifier = 0;
+      VkDrmFormatModifierPropertiesEXT mod_props;
+
+      if (!vn_android_get_gralloc_buffer_info(handle, strides, offsets,
+                                              &format_modifier))
+         return VK_ERROR_INVALID_EXTERNAL_HANDLE;
+
+      result = vn_android_get_modifier_properties(
+         vn_physical_device_to_handle(dev->physical_device),
+         image_info->format, format_modifier, alloc, &mod_props);
+      if (result != VK_SUCCESS)
+         return result;
+
+      /* XXX fix plane count > 1 case for external memory  */
+      if (mod_props.drmFormatModifierPlaneCount != 1) {
+         vn_log(dev->instance, "plane count is %d, expected 1",
+                mod_props.drmFormatModifierPlaneCount);
+         return VK_ERROR_INVALID_EXTERNAL_HANDLE;
+      }
+
+      const VkSubresourceLayout layout = {
+         .offset = offsets[0],
+         .size = 0,
+         .rowPitch = strides[0],
+         .arrayPitch = 0,
+         .depthPitch = 0,
+      };
+      const VkImageDrmFormatModifierExplicitCreateInfoEXT drm_mod_info = {
+         .sType =
+            VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT,
+         .pNext = image_info->pNext,
+         .drmFormatModifier = format_modifier,
+         .drmFormatModifierPlaneCount = 1,
+         .pPlaneLayouts = &layout,
+      };
+      const VkExternalMemoryImageCreateInfo external_img_info = {
+         .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
+         .pNext = &drm_mod_info,
+         .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
+      };
+      image_info->pNext = &external_img_info;
+      image_info->tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
+      result = vn_image_init_deferred(dev, image_info, img);
+      if (result != VK_SUCCESS)
+         return result;
+
+      /* For AHB memory allocation of a dedicated image, allocationSize must
+       * be zero from the app side. So we need to get the proper allocation
+       * size here used to override memory allocation info.
+       */
+      VkMemoryRequirements mem_req;
+      vn_GetImageMemoryRequirements(vn_device_to_handle(dev),
+                                    dedicated_info->image, &mem_req);
+      alloc_size = mem_req.size;
+   }
+
+   errno = 0;
+   dup_fd = os_dupfd_cloexec(dma_buf_fd);
+   if (dup_fd < 0)
+      return (errno == EMFILE) ? VK_ERROR_TOO_MANY_OBJECTS
+                               : VK_ERROR_OUT_OF_HOST_MEMORY;
+
+   /* Spec requires AHB export info to be present, so we must strip it. In
+    * practice, the AHB import path here only needs the main allocation info
+    * and the dedicated_info.
+    */
+   VkMemoryDedicatedAllocateInfo local_dedicated_info;
+   /* Override when dedicated_info exists and is not the tail struct. */
+   if (dedicated_info && dedicated_info->pNext) {
+      local_dedicated_info = *dedicated_info;
+      local_dedicated_info.pNext = NULL;
+      dedicated_info = &local_dedicated_info;
+   }
+   const VkMemoryAllocateInfo local_alloc_info = {
+      .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
+      .pNext = dedicated_info,
+      .allocationSize = alloc_size,
+      .memoryTypeIndex = alloc_info->memoryTypeIndex,
+   };
+   result =
+      vn_device_memory_import_dmabuf(dev, mem, &local_alloc_info, dup_fd);
+   if (result != VK_SUCCESS) {
+      close(dup_fd);
+      return result;
+   }
+
+   AHardwareBuffer_acquire(ahb);
+   mem->ahb = ahb;
+
+   return VK_SUCCESS;
 }
 
 VkResult
@@ -987,5 +1101,54 @@ vn_android_device_allocate_ahb(struct vn_device *dev,
                                struct vn_device_memory *mem,
                                const VkMemoryAllocateInfo *alloc_info)
 {
-   return VK_ERROR_OUT_OF_HOST_MEMORY;
+   const VkMemoryDedicatedAllocateInfo *dedicated_info =
+      vk_find_struct_const(alloc_info->pNext, MEMORY_DEDICATED_ALLOCATE_INFO);
+   uint32_t width = 0;
+   uint32_t height = 1;
+   uint32_t layers = 1;
+   uint32_t format = 0;
+   uint64_t usage = 0;
+   struct AHardwareBuffer *ahb = NULL;
+
+   if (dedicated_info && dedicated_info->image != VK_NULL_HANDLE) {
+      const VkImageCreateInfo *image_info =
+         &vn_image_from_handle(dedicated_info->image)->deferred_info->create;
+      assert(image_info);
+      width = image_info->extent.width;
+      height = image_info->extent.height;
+      layers = image_info->arrayLayers;
+      format = vn_android_ahb_format_from_vk_format(image_info->format);
+      /* TODO Need to further resolve the gralloc usage bits for image format
+       * list info, which might involve disabling compression if there exists
+       * no universally applied compression strategy across the formats.
+       */
+      usage = vn_android_get_ahb_usage(image_info->usage, image_info->flags);
+   } else {
+      width = alloc_info->allocationSize;
+      format = AHARDWAREBUFFER_FORMAT_BLOB;
+      /* TODO AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER is not supported by cros
+       * gralloc. So here we work around with CPU usage bits for VkBuffer.
+       */
+      usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
+              AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
+   }
+
+   ahb = vn_android_ahb_allocate(width, height, layers, format, usage);
+   if (!ahb)
+      return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+   VkResult result = vn_android_device_import_ahb(dev, mem, alloc_info, ahb);
+
+   /* ahb alloc has already acquired a ref and import will acquire another,
+    * must release one here to avoid leak.
+    */
+   AHardwareBuffer_release(ahb);
+
+   return result;
+}
+
+void
+vn_android_release_ahb(struct AHardwareBuffer *ahb)
+{
+   AHardwareBuffer_release(ahb);
 }
diff --git a/src/virtio/vulkan/vn_android.h b/src/virtio/vulkan/vn_android.h
index 960708b013a..e01ab489391 100644
--- a/src/virtio/vulkan/vn_android.h
+++ b/src/virtio/vulkan/vn_android.h
@@ -78,6 +78,9 @@ vn_android_device_allocate_ahb(struct vn_device *dev,
                                struct vn_device_memory *mem,
                                const VkMemoryAllocateInfo *alloc_info);
 
+void
+vn_android_release_ahb(struct AHardwareBuffer *ahb);
+
 #else
 
 static inline VkResult
@@ -151,6 +154,12 @@ vn_android_device_allocate_ahb(UNUSED struct vn_device *dev,
    return VK_ERROR_OUT_OF_HOST_MEMORY;
 }
 
+static inline void
+vn_android_release_ahb(UNUSED struct AHardwareBuffer *ahb)
+{
+   return;
+}
+
 #endif /* ANDROID */
 
 #endif /* VN_ANDROID_H */
diff --git a/src/virtio/vulkan/vn_device_memory.c b/src/virtio/vulkan/vn_device_memory.c
index 8ab8415e94d..12ccd11221e 100644
--- a/src/virtio/vulkan/vn_device_memory.c
+++ b/src/virtio/vulkan/vn_device_memory.c
@@ -344,6 +344,9 @@ vn_FreeMemory(VkDevice device,
       vn_async_vkFreeMemory(dev->instance, device, memory, NULL);
    }
 
+   if (mem->ahb)
+      vn_android_release_ahb(mem->ahb);
+
    vn_object_base_fini(&mem->base);
    vk_free(alloc, mem);
 }
diff --git a/src/virtio/vulkan/vn_device_memory.h b/src/virtio/vulkan/vn_device_memory.h
index 564d08221e1..4280022d5f3 100644
--- a/src/virtio/vulkan/vn_device_memory.h
+++ b/src/virtio/vulkan/vn_device_memory.h
@@ -31,6 +31,9 @@ struct vn_device_memory {
    VkDeviceSize base_offset;
 
    VkDeviceSize map_end;
+
+   /* non-NULL when backed by AHB */
+   struct AHardwareBuffer *ahb;
 };
 VK_DEFINE_NONDISP_HANDLE_CASTS(vn_device_memory,
                                base.base,



More information about the mesa-commit mailing list