Mesa (master): venus: implement VK_ANDROID_native_buffer v7

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Tue Apr 27 00:25:55 UTC 2021


Module: Mesa
Branch: master
Commit: 34f37fb780e1c7e29d524658b0af84ed03d514a0
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=34f37fb780e1c7e29d524658b0af84ed03d514a0

Author: Yiwei Zhang <zzyiwei at chromium.org>
Date:   Mon Apr 12 01:33:05 2021 +0000

venus: implement VK_ANDROID_native_buffer v7

1. Android native buffer import
2. vkGetSwapchainGrallocUsage2ANDROID
3. vkAcquireImageANDROID
4. vkQueueSignalReleaseImageANDROID
5. not advertise shared presentable image support

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/10259>

---

 src/virtio/vulkan/meson.build  |   2 +
 src/virtio/vulkan/vn_android.c | 261 +++++++++++++++++++++++++++++++++++++++++
 src/virtio/vulkan/vn_android.h |  30 +++++
 src/virtio/vulkan/vn_device.c  |  64 +++++++---
 src/virtio/vulkan/vn_image.c   |  13 ++
 src/virtio/vulkan/vn_image.h   |   2 +
 6 files changed, 354 insertions(+), 18 deletions(-)

diff --git a/src/virtio/vulkan/meson.build b/src/virtio/vulkan/meson.build
index 2de33de0722..69ecfa4901f 100644
--- a/src/virtio/vulkan/meson.build
+++ b/src/virtio/vulkan/meson.build
@@ -86,6 +86,8 @@ endif
 
 if with_platform_android
   libvn_files += files('vn_android.c')
+  vn_deps += dep_android
+  vn_flags += '-DVK_USE_PLATFORM_ANDROID_KHR'
 endif
 
 libvulkan_virtio = shared_library(
diff --git a/src/virtio/vulkan/vn_android.c b/src/virtio/vulkan/vn_android.c
index 7f44e97ca44..5948440b921 100644
--- a/src/virtio/vulkan/vn_android.c
+++ b/src/virtio/vulkan/vn_android.c
@@ -1,13 +1,27 @@
 /*
  * Copyright 2021 Google LLC
  * SPDX-License-Identifier: MIT
+ *
+ * based in part on anv and radv which are:
+ * Copyright © 2015 Intel Corporation
+ * Copyright © 2016 Red Hat
+ * Copyright © 2016 Bas Nieuwenhuizen
  */
 
+#include "vn_android.h"
 #include "vn_common.h"
 
 #include <hardware/hwvulkan.h>
+#include <vndk/hardware_buffer.h>
 #include <vulkan/vk_icd.h>
 
+#include "util/libsync.h"
+#include "util/os_file.h"
+
+#include "vn_device.h"
+#include "vn_image.h"
+#include "vn_queue.h"
+
 static int
 vn_hal_open(const struct hw_module_t *mod,
             const char *id,
@@ -62,3 +76,250 @@ vn_hal_open(const struct hw_module_t *mod,
    *dev = &vn_hal_dev.common;
    return 0;
 }
+
+VkResult
+vn_GetSwapchainGrallocUsage2ANDROID(
+   VkDevice device,
+   VkFormat format,
+   VkImageUsageFlags imageUsage,
+   VkSwapchainImageUsageFlagsANDROID swapchainImageUsage,
+   uint64_t *grallocConsumerUsage,
+   uint64_t *grallocProducerUsage)
+{
+   struct vn_device *dev = vn_device_from_handle(device);
+   *grallocConsumerUsage = 0;
+   *grallocProducerUsage = 0;
+
+   if (swapchainImageUsage & VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID)
+      return vn_error(dev->instance, VK_ERROR_INITIALIZATION_FAILED);
+
+   if (VN_DEBUG(WSI))
+      vn_log(dev->instance, "format=%d, imageUsage=0x%x", format, imageUsage);
+
+   if (imageUsage & (VK_IMAGE_USAGE_TRANSFER_DST_BIT |
+                     VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT))
+      *grallocProducerUsage |= AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER;
+
+   if (imageUsage &
+       (VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
+        VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT))
+      *grallocConsumerUsage |= AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
+
+   return VK_SUCCESS;
+}
+
+VkResult
+vn_image_from_anb(struct vn_device *dev,
+                  const VkImageCreateInfo *image_info,
+                  const VkNativeBufferANDROID *anb_info,
+                  const VkAllocationCallbacks *alloc,
+                  struct vn_image **out_img)
+{
+   /* If anb_info->handle points to a classic resouce created from
+    * virtio_gpu_cmd_resource_create_3d, anb_info->stride is the stride of the
+    * guest shadow storage other than the host gpu storage.
+    *
+    * We also need to pass the correct stride to vn_CreateImage, which will be
+    * done via VkImageDrmFormatModifierExplicitCreateInfoEXT and will require
+    * VK_EXT_image_drm_format_modifier support in the host driver. The struct
+    * also needs a modifier, which can only be encoded in anb_info->handle.
+    *
+    * Given above, until gralloc gets fixed to set stride correctly and to
+    * encode modifier in the native handle, we will have to make assumptions.
+    * (e.g. In CrOS, there's a VIRTGPU_RESOURCE_INFO_TYPE_EXTENDED kernel hack
+    * for that)
+    */
+   VkResult result = VK_SUCCESS;
+   VkDevice device = vn_device_to_handle(dev);
+   VkDeviceMemory memory = VK_NULL_HANDLE;
+   VkImage image = VK_NULL_HANDLE;
+   struct vn_image *img = NULL;
+   uint32_t mem_type_bits = 0;
+   int dma_buf_fd = -1;
+   int dup_fd = -1;
+
+   /* encoder will strip the Android specific pNext structs */
+   result = vn_image_create(dev, image_info, alloc, &img);
+   if (result != VK_SUCCESS)
+      goto fail;
+
+   image = vn_image_to_handle(img);
+   VkMemoryRequirements mem_req;
+   vn_GetImageMemoryRequirements(device, image, &mem_req);
+   if (!mem_req.memoryTypeBits) {
+      result = VK_ERROR_INVALID_EXTERNAL_HANDLE;
+      goto fail;
+   }
+
+   if (anb_info->handle->numFds != 1) {
+      if (VN_DEBUG(WSI))
+         vn_log(dev->instance, "handle->numFds is %d, expected 1",
+                anb_info->handle->numFds);
+      result = VK_ERROR_INVALID_EXTERNAL_HANDLE;
+      goto fail;
+   }
+
+   dma_buf_fd = anb_info->handle->data[0];
+   if (dma_buf_fd < 0) {
+      result = VK_ERROR_INVALID_EXTERNAL_HANDLE;
+      goto fail;
+   }
+
+   VkMemoryFdPropertiesKHR fd_prop = {
+      .sType = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR,
+      .pNext = NULL,
+      .memoryTypeBits = 0,
+   };
+   result = vn_GetMemoryFdPropertiesKHR(
+      device, VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, dma_buf_fd,
+      &fd_prop);
+   if (result != VK_SUCCESS)
+      goto fail;
+
+   if (!fd_prop.memoryTypeBits) {
+      result = VK_ERROR_INVALID_EXTERNAL_HANDLE;
+      goto fail;
+   }
+
+   if (VN_DEBUG(WSI))
+      vn_log(dev->instance, "memoryTypeBits = img(0x%X) & fd(0x%X)",
+             mem_req.memoryTypeBits, fd_prop.memoryTypeBits);
+
+   mem_type_bits = mem_req.memoryTypeBits & fd_prop.memoryTypeBits;
+   if (!mem_type_bits) {
+      result = VK_ERROR_INVALID_EXTERNAL_HANDLE;
+      goto fail;
+   }
+
+   dup_fd = os_dupfd_cloexec(dma_buf_fd);
+   if (dup_fd < 0) {
+      result = (errno == EMFILE) ? VK_ERROR_TOO_MANY_OBJECTS
+                                 : VK_ERROR_OUT_OF_HOST_MEMORY;
+      goto fail;
+   }
+
+   const VkImportMemoryFdInfoKHR import_fd_info = {
+      .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
+      .pNext = NULL,
+      .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
+      .fd = dup_fd,
+   };
+   const VkMemoryAllocateInfo memory_info = {
+      .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
+      .pNext = &import_fd_info,
+      .allocationSize = mem_req.size,
+      .memoryTypeIndex = ffs(mem_type_bits) - 1,
+   };
+   result = vn_AllocateMemory(device, &memory_info, alloc, &memory);
+   if (result != VK_SUCCESS) {
+      /* only need to close the dup_fd on import failure */
+      close(dup_fd);
+      goto fail;
+   }
+
+   result = vn_BindImageMemory(device, image, memory, 0);
+   if (result != VK_SUCCESS)
+      goto fail;
+
+   /* Android WSI image owns the memory */
+   img->private_memory = memory;
+   *out_img = img;
+
+   return VK_SUCCESS;
+
+fail:
+   if (image != VK_NULL_HANDLE)
+      vn_DestroyImage(device, image, alloc);
+   if (memory != VK_NULL_HANDLE)
+      vn_FreeMemory(device, memory, alloc);
+   return vn_error(dev->instance, result);
+}
+
+VkResult
+vn_AcquireImageANDROID(VkDevice device,
+                       UNUSED VkImage image,
+                       int nativeFenceFd,
+                       VkSemaphore semaphore,
+                       VkFence fence)
+{
+   /* At this moment, out semaphore and fence are filled with already signaled
+    * payloads, and the native fence fd is waited inside until signaled.
+    */
+   struct vn_device *dev = vn_device_from_handle(device);
+   struct vn_semaphore *sem = vn_semaphore_from_handle(semaphore);
+   struct vn_fence *fen = vn_fence_from_handle(fence);
+
+   if (nativeFenceFd >= 0) {
+      int ret = sync_wait(nativeFenceFd, INT32_MAX);
+      /* Android loader expects the ICD to always close the fd */
+      close(nativeFenceFd);
+      if (ret)
+         return vn_error(dev->instance, VK_ERROR_SURFACE_LOST_KHR);
+   }
+
+   if (sem)
+      vn_semaphore_signal_wsi(dev, sem);
+
+   if (fen)
+      vn_fence_signal_wsi(dev, fen);
+
+   return VK_SUCCESS;
+}
+
+VkResult
+vn_QueueSignalReleaseImageANDROID(VkQueue queue,
+                                  uint32_t waitSemaphoreCount,
+                                  const VkSemaphore *pWaitSemaphores,
+                                  VkImage image,
+                                  int *pNativeFenceFd)
+{
+   /* At this moment, the wait semaphores are converted to a VkFence via an
+    * empty submit. The VkFence is then waited inside until signaled, and the
+    * out native fence fd is set to -1.
+    */
+   VkResult result = VK_SUCCESS;
+   struct vn_queue *que = vn_queue_from_handle(queue);
+   const VkAllocationCallbacks *alloc = &que->device->base.base.alloc;
+   VkDevice device = vn_device_to_handle(que->device);
+   VkPipelineStageFlags local_stage_masks[8];
+   VkPipelineStageFlags *stage_masks = local_stage_masks;
+
+   if (waitSemaphoreCount == 0)
+      goto out;
+
+   if (waitSemaphoreCount > ARRAY_SIZE(local_stage_masks)) {
+      stage_masks =
+         vk_alloc(alloc, sizeof(VkPipelineStageFlags) * waitSemaphoreCount,
+                  VN_DEFAULT_ALIGN, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
+      if (!stage_masks) {
+         result = VK_ERROR_OUT_OF_HOST_MEMORY;
+         goto out;
+      }
+   }
+
+   for (uint32_t i = 0; i < waitSemaphoreCount; i++)
+      stage_masks[i] = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
+
+   const VkSubmitInfo submit_info = {
+      .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
+      .pNext = NULL,
+      .waitSemaphoreCount = waitSemaphoreCount,
+      .pWaitSemaphores = pWaitSemaphores,
+      .pWaitDstStageMask = stage_masks,
+      .commandBufferCount = 0,
+      .pCommandBuffers = NULL,
+      .signalSemaphoreCount = 0,
+      .pSignalSemaphores = NULL,
+   };
+   result = vn_QueueSubmit(queue, 1, &submit_info, que->wait_fence);
+   if (result != VK_SUCCESS)
+      goto out;
+
+   result =
+      vn_WaitForFences(device, 1, &que->wait_fence, VK_TRUE, UINT64_MAX);
+   vn_ResetFences(device, 1, &que->wait_fence);
+
+out:
+   *pNativeFenceFd = -1;
+   return result;
+}
diff --git a/src/virtio/vulkan/vn_android.h b/src/virtio/vulkan/vn_android.h
new file mode 100644
index 00000000000..f18ce7f2694
--- /dev/null
+++ b/src/virtio/vulkan/vn_android.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2021 Google LLC
+ * SPDX-License-Identifier: MIT
+ *
+ * based in part on anv and radv which are:
+ * Copyright © 2015 Intel Corporation
+ * Copyright © 2016 Red Hat
+ * Copyright © 2016 Bas Nieuwenhuizen
+ */
+
+#ifndef VN_ANDROID_H
+#define VN_ANDROID_H
+
+#include <vulkan/vk_android_native_buffer.h>
+#include <vulkan/vulkan.h>
+
+/* venus implements VK_ANDROID_native_buffer up to spec version 7 */
+#define VN_ANDROID_NATIVE_BUFFER_SPEC_VERSION 7
+
+struct vn_device;
+struct vn_image;
+
+VkResult
+vn_image_from_anb(struct vn_device *dev,
+                  const VkImageCreateInfo *image_info,
+                  const VkNativeBufferANDROID *anb_info,
+                  const VkAllocationCallbacks *alloc,
+                  struct vn_image **out_img);
+
+#endif /* VN_ANDROID_H */
diff --git a/src/virtio/vulkan/vn_device.c b/src/virtio/vulkan/vn_device.c
index ba57cadad5a..a45c72a2e85 100644
--- a/src/virtio/vulkan/vn_device.c
+++ b/src/virtio/vulkan/vn_device.c
@@ -20,6 +20,7 @@
 #include "venus-protocol/vn_protocol_driver_instance.h"
 #include "venus-protocol/vn_protocol_driver_transport.h"
 
+#include "vn_android.h"
 #include "vn_device_memory.h"
 #include "vn_icd.h"
 #include "vn_queue.h"
@@ -1413,6 +1414,9 @@ vn_physical_device_get_supported_extensions(
       .KHR_incremental_present = true,
       .KHR_swapchain = true,
       .KHR_swapchain_mutable_format = true,
+#endif
+#ifdef ANDROID
+      .ANDROID_native_buffer = true,
 #endif
    };
 
@@ -1535,6 +1539,13 @@ vn_physical_device_init_extensions(struct vn_physical_device *physical_dev)
       if (supported.extensions[i]) {
          physical_dev->base.base.supported_extensions.extensions[i] = true;
          physical_dev->extension_spec_versions[i] = props->specVersion;
+#ifdef ANDROID
+         /* override VK_ANDROID_native_buffer spec version */
+         if (!strcmp(props->extensionName,
+                     VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME))
+            physical_dev->extension_spec_versions[i] =
+               VN_ANDROID_NATIVE_BUFFER_SPEC_VERSION;
+#endif
          continue;
       }
 
@@ -2380,12 +2391,13 @@ vn_GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice,
 
       VkPhysicalDevicePCIBusInfoPropertiesEXT *pci_bus_info;
       VkPhysicalDeviceTransformFeedbackPropertiesEXT *transform_feedback;
+      VkPhysicalDevicePresentationPropertiesANDROID *presentation_properties;
    } u;
 
    u.pnext = (VkBaseOutStructure *)pProperties;
    while (u.pnext) {
       void *saved = u.pnext->pNext;
-      switch (u.pnext->sType) {
+      switch ((int32_t)u.pnext->sType) {
       case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2:
          memcpy(u.pnext, &physical_dev->properties,
                 sizeof(physical_dev->properties));
@@ -2576,6 +2588,9 @@ vn_GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice,
                 &physical_dev->transform_feedback_properties,
                 sizeof(physical_dev->transform_feedback_properties));
          break;
+      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENTATION_PROPERTIES_ANDROID:
+         u.presentation_properties->sharedImage = VK_FALSE;
+         break;
       default:
          break;
       }
@@ -2908,52 +2923,65 @@ find_extension_names(const char *const *exts,
    return false;
 }
 
-static const char **
+static bool
 merge_extension_names(const char *const *exts,
                       uint32_t ext_count,
                       const char *const *extra_exts,
                       uint32_t extra_count,
+                      const char *const *block_exts,
+                      uint32_t block_count,
                       const VkAllocationCallbacks *alloc,
-                      uint32_t *merged_count)
+                      const char *const **out_exts,
+                      uint32_t *out_count)
 {
    const char **merged =
       vk_alloc(alloc, sizeof(*merged) * (ext_count + extra_count),
                VN_DEFAULT_ALIGN, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
    if (!merged)
-      return NULL;
-
-   memcpy(merged, exts, sizeof(*exts) * ext_count);
+      return false;
 
-   uint32_t count = ext_count;
+   uint32_t count = 0;
+   for (uint32_t i = 0; i < ext_count; i++) {
+      if (!find_extension_names(block_exts, block_count, exts[i]))
+         merged[count++] = exts[i];
+   }
    for (uint32_t i = 0; i < extra_count; i++) {
       if (!find_extension_names(exts, ext_count, extra_exts[i]))
          merged[count++] = extra_exts[i];
    }
 
-   *merged_count = count;
-   return merged;
+   *out_exts = merged;
+   *out_count = count;
+   return true;
 }
 
 static const VkDeviceCreateInfo *
-vn_device_fix_create_info(const struct vn_physical_device *physical_dev,
+vn_device_fix_create_info(const struct vn_device *dev,
                           const VkDeviceCreateInfo *dev_info,
                           const VkAllocationCallbacks *alloc,
                           VkDeviceCreateInfo *local_info)
 {
+   /* extra_exts and block_exts must not overlap */
    const char *extra_exts[8];
+   const char *block_exts[8];
    uint32_t extra_count = 0;
+   uint32_t block_count = 0;
 
-   if (physical_dev->wsi_device.supports_modifiers)
+   if (dev->physical_device->wsi_device.supports_modifiers)
       extra_exts[extra_count++] = "VK_EXT_image_drm_format_modifier";
 
-   if (!extra_count)
+   if (dev->base.base.enabled_extensions.ANDROID_native_buffer)
+      block_exts[block_count++] = VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME;
+
+   if (!extra_count && (!block_count || !dev_info->enabledExtensionCount))
       return dev_info;
 
    *local_info = *dev_info;
-   local_info->ppEnabledExtensionNames = merge_extension_names(
-      dev_info->ppEnabledExtensionNames, dev_info->enabledExtensionCount,
-      extra_exts, extra_count, alloc, &local_info->enabledExtensionCount);
-   if (!local_info->ppEnabledExtensionNames)
+   if (!merge_extension_names(dev_info->ppEnabledExtensionNames,
+                              dev_info->enabledExtensionCount, extra_exts,
+                              extra_count, block_exts, block_count, alloc,
+                              &local_info->ppEnabledExtensionNames,
+                              &local_info->enabledExtensionCount))
       return NULL;
 
    return local_info;
@@ -2992,8 +3020,8 @@ vn_CreateDevice(VkPhysicalDevice physicalDevice,
    dev->physical_device = physical_dev;
 
    VkDeviceCreateInfo local_create_info;
-   pCreateInfo = vn_device_fix_create_info(physical_dev, pCreateInfo, alloc,
-                                           &local_create_info);
+   pCreateInfo =
+      vn_device_fix_create_info(dev, pCreateInfo, alloc, &local_create_info);
    if (!pCreateInfo) {
       result = VK_ERROR_OUT_OF_HOST_MEMORY;
       goto fail;
diff --git a/src/virtio/vulkan/vn_image.c b/src/virtio/vulkan/vn_image.c
index df29ecfee05..6e86c8aaba9 100644
--- a/src/virtio/vulkan/vn_image.c
+++ b/src/virtio/vulkan/vn_image.c
@@ -15,6 +15,7 @@
 #include "venus-protocol/vn_protocol_driver_sampler.h"
 #include "venus-protocol/vn_protocol_driver_sampler_ycbcr_conversion.h"
 
+#include "vn_android.h"
 #include "vn_device.h"
 #include "vn_device_memory.h"
 
@@ -153,6 +154,15 @@ vn_CreateImage(VkDevice device,
    }
 #endif
 
+#ifdef ANDROID
+   const VkNativeBufferANDROID *anb_info =
+      vk_find_struct_const(pCreateInfo->pNext, NATIVE_BUFFER_ANDROID);
+   if (anb_info) {
+      result = vn_image_from_anb(dev, pCreateInfo, anb_info, alloc, &img);
+      goto out;
+   }
+#endif
+
    result = vn_image_create(dev, pCreateInfo, alloc, &img);
 
 out:
@@ -176,6 +186,9 @@ vn_DestroyImage(VkDevice device,
    if (!img)
       return;
 
+   if (img->private_memory != VK_NULL_HANDLE)
+      vn_FreeMemory(device, img->private_memory, pAllocator);
+
    vn_async_vkDestroyImage(dev->instance, device, image, NULL);
 
    vn_object_base_fini(&img->base);
diff --git a/src/virtio/vulkan/vn_image.h b/src/virtio/vulkan/vn_image.h
index 46f388dd98a..f134ca2640a 100644
--- a/src/virtio/vulkan/vn_image.h
+++ b/src/virtio/vulkan/vn_image.h
@@ -18,6 +18,8 @@ struct vn_image {
 
    VkMemoryRequirements2 memory_requirements[4];
    VkMemoryDedicatedRequirements dedicated_requirements[4];
+   /* For VK_ANDROID_native_buffer, the WSI image owns the memory, */
+   VkDeviceMemory private_memory;
 };
 VK_DEFINE_NONDISP_HANDLE_CASTS(vn_image,
                                base.base,



More information about the mesa-commit mailing list