Mesa (main): v3dv: add Android support

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Tue Dec 21 09:53:29 UTC 2021


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

Author: Roman Stratiienko <r.stratiienko at gmail.com>
Date:   Wed Dec  8 12:15:38 2021 +0200

v3dv: add Android support

Acknowledgements to android-rpi team and lineage-rpi maintainer (KonstaT)
for creating/testing initial vulkan support. Their experience was used as
a baseline for this work.

Most of the code is a copy of turnip and anv.
Improved by cleaning dEQP failures:

 - Improved gralloc support (use allocation time stride, size, modifier).
 - Fixed some dEQP crashes due to memory allocation issues.

Reviewed-by: Iago Toral Quiroga <itoral at igalia.com>
Signed-off-by: Roman Stratiienko <r.stratiienko at gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/14016>

---

 src/broadcom/vulkan/meson.build    |   6 +
 src/broadcom/vulkan/v3dv_android.c | 539 +++++++++++++++++++++++++++++++++++++
 src/broadcom/vulkan/v3dv_device.c  |   3 +
 src/broadcom/vulkan/v3dv_image.c   |  41 +++
 src/broadcom/vulkan/v3dv_private.h |  30 +++
 5 files changed, 619 insertions(+)

diff --git a/src/broadcom/vulkan/meson.build b/src/broadcom/vulkan/meson.build
index bfa7e9f29f2..f86598ee95e 100644
--- a/src/broadcom/vulkan/meson.build
+++ b/src/broadcom/vulkan/meson.build
@@ -98,6 +98,12 @@ if with_platform_wayland
   libv3dv_files += [wayland_drm_client_protocol_h, wayland_drm_protocol_c]
 endif
 
+if with_platform_android
+  v3dv_deps += dep_android
+  v3dv_flags += '-DVK_USE_PLATFORM_ANDROID_KHR'
+  libv3dv_files += files('v3dv_android.c')
+endif
+
 per_version_libs = []
 foreach ver : v3d_versions
   per_version_libs += static_library(
diff --git a/src/broadcom/vulkan/v3dv_android.c b/src/broadcom/vulkan/v3dv_android.c
new file mode 100644
index 00000000000..7ebc5a01adc
--- /dev/null
+++ b/src/broadcom/vulkan/v3dv_android.c
@@ -0,0 +1,539 @@
+/*
+ * Copyright © 2017, Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "v3dv_private.h"
+#include <hardware/gralloc.h>
+
+#if ANDROID_API_LEVEL >= 26
+#include <hardware/gralloc1.h>
+#endif
+
+#include "drm-uapi/drm_fourcc.h"
+#include <hardware/hardware.h>
+#include <hardware/hwvulkan.h>
+
+#include <vulkan/vk_android_native_buffer.h>
+#include <vulkan/vk_icd.h>
+
+#include "util/libsync.h"
+#include "util/log.h"
+#include "util/os_file.h"
+
+static int
+v3dv_hal_open(const struct hw_module_t *mod,
+              const char *id,
+              struct hw_device_t **dev);
+static int
+v3dv_hal_close(struct hw_device_t *dev);
+
+static void UNUSED
+static_asserts(void)
+{
+   STATIC_ASSERT(HWVULKAN_DISPATCH_MAGIC == ICD_LOADER_MAGIC);
+}
+
+PUBLIC struct hwvulkan_module_t HAL_MODULE_INFO_SYM = {
+   .common =
+     {
+       .tag = HARDWARE_MODULE_TAG,
+       .module_api_version = HWVULKAN_MODULE_API_VERSION_0_1,
+       .hal_api_version = HARDWARE_MAKE_API_VERSION(1, 0),
+       .id = HWVULKAN_HARDWARE_MODULE_ID,
+       .name = "Broadcom Vulkan HAL",
+       .author = "Mesa3D",
+       .methods =
+         &(hw_module_methods_t) {
+           .open = v3dv_hal_open,
+         },
+     },
+};
+
+/* If any bits in test_mask are set, then unset them and return true. */
+static inline bool
+unmask32(uint32_t *inout_mask, uint32_t test_mask)
+{
+   uint32_t orig_mask = *inout_mask;
+   *inout_mask &= ~test_mask;
+   return *inout_mask != orig_mask;
+}
+
+static int
+v3dv_hal_open(const struct hw_module_t *mod,
+              const char *id,
+              struct hw_device_t **dev)
+{
+   assert(mod == &HAL_MODULE_INFO_SYM.common);
+   assert(strcmp(id, HWVULKAN_DEVICE_0) == 0);
+
+   hwvulkan_device_t *hal_dev = malloc(sizeof(*hal_dev));
+   if (!hal_dev)
+      return -1;
+
+   *hal_dev = (hwvulkan_device_t){
+      .common =
+        {
+          .tag = HARDWARE_DEVICE_TAG,
+          .version = HWVULKAN_DEVICE_API_VERSION_0_1,
+          .module = &HAL_MODULE_INFO_SYM.common,
+          .close = v3dv_hal_close,
+        },
+     .EnumerateInstanceExtensionProperties =
+        v3dv_EnumerateInstanceExtensionProperties,
+     .CreateInstance = v3dv_CreateInstance,
+     .GetInstanceProcAddr = v3dv_GetInstanceProcAddr,
+   };
+
+   mesa_logi("v3dv: Warning: Android Vulkan implementation is experimental");
+
+   *dev = &hal_dev->common;
+   return 0;
+}
+
+static int
+v3dv_hal_close(struct hw_device_t *dev)
+{
+   /* hwvulkan.h claims that hw_device_t::close() is never called. */
+   return -1;
+}
+
+static int
+get_format_bpp(int native)
+{
+   int bpp;
+
+   switch (native) {
+   case HAL_PIXEL_FORMAT_RGBA_FP16:
+      bpp = 8;
+      break;
+   case HAL_PIXEL_FORMAT_RGBA_8888:
+   case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+   case HAL_PIXEL_FORMAT_RGBX_8888:
+   case HAL_PIXEL_FORMAT_BGRA_8888:
+   case HAL_PIXEL_FORMAT_RGBA_1010102:
+      bpp = 4;
+      break;
+   case HAL_PIXEL_FORMAT_RGB_565:
+      bpp = 2;
+      break;
+   default:
+      bpp = 0;
+      break;
+   }
+
+   return bpp;
+}
+
+/* get buffer info from VkNativeBufferANDROID */
+static VkResult
+v3dv_gralloc_info_other(struct v3dv_device *device,
+                        const VkNativeBufferANDROID *native_buffer,
+                        int *out_stride,
+                        uint64_t *out_modifier)
+{
+   *out_stride = native_buffer->stride /*in pixels*/ *
+                 get_format_bpp(native_buffer->format);
+   *out_modifier = DRM_FORMAT_MOD_LINEAR;
+   return VK_SUCCESS;
+}
+
+static const char cros_gralloc_module_name[] = "CrOS Gralloc";
+
+#define CROS_GRALLOC_DRM_GET_BUFFER_INFO 4
+
+struct cros_gralloc0_buffer_info
+{
+   uint32_t drm_fourcc;
+   int num_fds;
+   int fds[4];
+   uint64_t modifier;
+   int offset[4];
+   int stride[4];
+};
+
+static VkResult
+v3dv_gralloc_info_cros(struct v3dv_device *device,
+                       const VkNativeBufferANDROID *native_buffer,
+                       int *out_stride,
+                       uint64_t *out_modifier)
+{
+   const gralloc_module_t *gralloc = device->gralloc;
+   struct cros_gralloc0_buffer_info info;
+   int ret;
+
+   ret = gralloc->perform(gralloc, CROS_GRALLOC_DRM_GET_BUFFER_INFO,
+                          native_buffer->handle, &info);
+   if (ret)
+      return VK_ERROR_INVALID_EXTERNAL_HANDLE;
+
+   *out_stride = info.stride[0];
+   *out_modifier = info.modifier;
+
+   return VK_SUCCESS;
+}
+
+VkResult
+v3dv_gralloc_info(struct v3dv_device *device,
+                  const VkNativeBufferANDROID *native_buffer,
+                  int *out_dmabuf,
+                  int *out_stride,
+                  int *out_size,
+                  uint64_t *out_modifier)
+{
+   if (device->gralloc_type == V3DV_GRALLOC_UNKNOWN) {
+      /* get gralloc module for gralloc buffer info query */
+      int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
+                              (const hw_module_t **) &device->gralloc);
+
+      device->gralloc_type = V3DV_GRALLOC_OTHER;
+
+      if (err == 0) {
+         const gralloc_module_t *gralloc = device->gralloc;
+         mesa_logi("opened gralloc module name: %s", gralloc->common.name);
+
+         if (strcmp(gralloc->common.name, cros_gralloc_module_name) == 0 &&
+             gralloc->perform) {
+            device->gralloc_type = V3DV_GRALLOC_CROS;
+         }
+      }
+   }
+
+   *out_dmabuf = native_buffer->handle->data[0];
+   *out_size = lseek(*out_dmabuf, 0, SEEK_END);
+
+   if (device->gralloc_type == V3DV_GRALLOC_CROS) {
+      return v3dv_gralloc_info_cros(device, native_buffer, out_stride,
+                                    out_modifier);
+   } else {
+      return v3dv_gralloc_info_other(device, native_buffer, out_stride,
+                                     out_modifier);
+   }
+}
+
+VkResult
+v3dv_import_native_buffer_fd(VkDevice device_h,
+                             int native_buffer_fd,
+                             const VkAllocationCallbacks *alloc,
+                             VkImage image_h)
+{
+   struct v3dv_image *image = NULL;
+   VkResult result;
+
+   image = v3dv_image_from_handle(image_h);
+
+   VkDeviceMemory memory_h;
+
+   const VkMemoryDedicatedAllocateInfo ded_alloc = {
+      .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
+      .pNext = NULL,
+      .buffer = VK_NULL_HANDLE,
+      .image = image_h
+   };
+
+   const VkImportMemoryFdInfoKHR import_info = {
+      .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
+      .pNext = &ded_alloc,
+      .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT,
+      .fd = os_dupfd_cloexec(native_buffer_fd),
+   };
+
+   result =
+      v3dv_AllocateMemory(device_h,
+                          &(VkMemoryAllocateInfo) {
+                             .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
+                             .pNext = &import_info,
+                             .allocationSize = image->size,
+                             .memoryTypeIndex = 0,
+                          },
+                          alloc, &memory_h);
+
+   if (result != VK_SUCCESS)
+      goto fail_create_image;
+
+   VkBindImageMemoryInfo bind_info = {
+      .sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO,
+      .image = image_h,
+      .memory = memory_h,
+      .memoryOffset = 0,
+   };
+   v3dv_BindImageMemory2(device_h, 1, &bind_info);
+
+   image->is_native_buffer_memory = true;
+
+   return VK_SUCCESS;
+
+fail_create_image:
+   close(import_info.fd);
+
+   return result;
+}
+
+static VkResult
+format_supported_with_usage(VkDevice device_h,
+                            VkFormat format,
+                            VkImageUsageFlags imageUsage)
+{
+   V3DV_FROM_HANDLE(v3dv_device, device, device_h);
+   struct v3dv_physical_device *phys_dev = &device->instance->physicalDevice;
+   VkPhysicalDevice phys_dev_h = v3dv_physical_device_to_handle(phys_dev);
+   VkResult result;
+
+   const VkPhysicalDeviceImageFormatInfo2 image_format_info = {
+      .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
+      .format = format,
+      .type = VK_IMAGE_TYPE_2D,
+      .tiling = VK_IMAGE_TILING_OPTIMAL,
+      .usage = imageUsage,
+   };
+
+   VkImageFormatProperties2 image_format_props = {
+      .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
+   };
+
+   /* Check that requested format and usage are supported. */
+   result = v3dv_GetPhysicalDeviceImageFormatProperties2(
+      phys_dev_h, &image_format_info, &image_format_props);
+   if (result != VK_SUCCESS) {
+      return vk_errorf(device, result,
+                       "v3dv_GetPhysicalDeviceImageFormatProperties2 failed "
+                       "inside %s",
+                       __func__);
+   }
+
+   return VK_SUCCESS;
+}
+
+static VkResult
+setup_gralloc0_usage(struct v3dv_device *device,
+                     VkFormat format,
+                     VkImageUsageFlags imageUsage,
+                     int *grallocUsage)
+{
+   if (unmask32(&imageUsage, VK_IMAGE_USAGE_TRANSFER_DST_BIT |
+                             VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT))
+      *grallocUsage |= GRALLOC_USAGE_HW_RENDER;
+
+   if (unmask32(&imageUsage, VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
+                             VK_IMAGE_USAGE_SAMPLED_BIT |
+                             VK_IMAGE_USAGE_STORAGE_BIT |
+                             VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT))
+      *grallocUsage |= GRALLOC_USAGE_HW_TEXTURE;
+
+   /* All VkImageUsageFlags not explicitly checked here are unsupported for
+    * gralloc swapchains.
+    */
+   if (imageUsage != 0) {
+      return vk_errorf(device, VK_ERROR_FORMAT_NOT_SUPPORTED,
+                       "unsupported VkImageUsageFlags(0x%x) for gralloc "
+                       "swapchain",
+                       imageUsage);
+   }
+
+   /* Swapchain assumes direct displaying, therefore enable COMPOSER flag,
+    * In case format is not supported by display controller, gralloc will
+    * drop this flag and still allocate the buffer in VRAM
+    */
+   *grallocUsage |= GRALLOC_USAGE_HW_COMPOSER;
+
+   if (*grallocUsage == 0)
+      return VK_ERROR_FORMAT_NOT_SUPPORTED;
+
+   return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL
+v3dv_GetSwapchainGrallocUsageANDROID(VkDevice device_h,
+                                     VkFormat format,
+                                     VkImageUsageFlags imageUsage,
+                                     int *grallocUsage)
+{
+   V3DV_FROM_HANDLE(v3dv_device, device, device_h);
+   VkResult result;
+
+   result = format_supported_with_usage(device_h, format, imageUsage);
+   if (result != VK_SUCCESS)
+      return result;
+
+   *grallocUsage = 0;
+   return setup_gralloc0_usage(device, format, imageUsage, grallocUsage);
+}
+
+#if ANDROID_API_LEVEL >= 26
+VKAPI_ATTR VkResult VKAPI_CALL
+v3dv_GetSwapchainGrallocUsage2ANDROID(
+   VkDevice device_h,
+   VkFormat format,
+   VkImageUsageFlags imageUsage,
+   VkSwapchainImageUsageFlagsANDROID swapchainImageUsage,
+   uint64_t *grallocConsumerUsage,
+   uint64_t *grallocProducerUsage)
+{
+   V3DV_FROM_HANDLE(v3dv_device, device, device_h);
+   VkResult result;
+
+   *grallocConsumerUsage = 0;
+   *grallocProducerUsage = 0;
+   mesa_logd("%s: format=%d, usage=0x%x", __func__, format, imageUsage);
+
+   result = format_supported_with_usage(device_h, format, imageUsage);
+   if (result != VK_SUCCESS)
+      return result;
+
+   int32_t grallocUsage = 0;
+   result = setup_gralloc0_usage(device, format, imageUsage, &grallocUsage);
+   if (result != VK_SUCCESS)
+      return result;
+
+   /* Setup gralloc1 usage flags from gralloc0 flags. */
+
+   if (grallocUsage & GRALLOC_USAGE_HW_RENDER) {
+      *grallocProducerUsage |= GRALLOC1_PRODUCER_USAGE_GPU_RENDER_TARGET;
+   }
+
+   if (grallocUsage & GRALLOC_USAGE_HW_TEXTURE) {
+      *grallocConsumerUsage |= GRALLOC1_CONSUMER_USAGE_GPU_TEXTURE;
+   }
+
+   if (grallocUsage & GRALLOC_USAGE_HW_COMPOSER) {
+      /* GPU composing case */
+      *grallocConsumerUsage |= GRALLOC1_CONSUMER_USAGE_GPU_TEXTURE;
+      /* Hardware composing case */
+      *grallocConsumerUsage |= GRALLOC1_CONSUMER_USAGE_HWCOMPOSER;
+   }
+
+   return VK_SUCCESS;
+}
+#endif
+
+VKAPI_ATTR VkResult VKAPI_CALL
+v3dv_AcquireImageANDROID(VkDevice device_h,
+                         VkImage image_h,
+                         int nativeFenceFd,
+                         VkSemaphore semaphore_h,
+                         VkFence fence_h)
+{
+   V3DV_FROM_HANDLE(v3dv_device, device, device_h);
+   VkResult result = VK_SUCCESS;
+
+   /* From https://source.android.com/devices/graphics/implement-vulkan :
+    *
+    *    "The driver takes ownership of the fence file descriptor and closes
+    *    the fence file descriptor when no longer needed. The driver must do
+    *    so even if neither a semaphore or fence object is provided, or even
+    *    if vkAcquireImageANDROID fails and returns an error."
+    *
+    * The Vulkan spec for VkImportFence/SemaphoreFdKHR(), however, requires
+    * the file descriptor to be left alone on failure.
+    */
+   int semaphore_fd = -1, fence_fd = -1;
+   if (nativeFenceFd >= 0) {
+      if (semaphore_h != VK_NULL_HANDLE && fence_h != VK_NULL_HANDLE) {
+         /* We have both so we have to import the sync file twice. One of
+          * them needs to be a dup.
+          */
+         semaphore_fd = nativeFenceFd;
+         fence_fd = os_dupfd_cloexec(nativeFenceFd);
+         if (fence_fd < 0) {
+            VkResult err = (errno == EMFILE) ? VK_ERROR_TOO_MANY_OBJECTS
+                                             : VK_ERROR_OUT_OF_HOST_MEMORY;
+            close(nativeFenceFd);
+            return vk_error(device, err);
+         }
+      } else if (semaphore_h != VK_NULL_HANDLE) {
+         semaphore_fd = nativeFenceFd;
+      } else if (fence_h != VK_NULL_HANDLE) {
+         fence_fd = nativeFenceFd;
+      } else {
+         /* Nothing to import into so we have to close the file */
+         close(nativeFenceFd);
+      }
+   }
+
+   if (semaphore_h != VK_NULL_HANDLE) {
+      const VkImportSemaphoreFdInfoKHR info = {
+         .sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR,
+         .semaphore = semaphore_h,
+         .flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT,
+         .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
+         .fd = semaphore_fd,
+      };
+      result = v3dv_ImportSemaphoreFdKHR(device_h, &info);
+      if (result == VK_SUCCESS)
+         semaphore_fd = -1; /* VK took ownership */
+   }
+
+   if (result == VK_SUCCESS && fence_h != VK_NULL_HANDLE) {
+      const VkImportFenceFdInfoKHR info = {
+         .sType = VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR,
+         .fence = fence_h,
+         .flags = VK_FENCE_IMPORT_TEMPORARY_BIT,
+         .handleType = VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT,
+         .fd = fence_fd,
+      };
+      result = v3dv_ImportFenceFdKHR(device_h, &info);
+      if (result == VK_SUCCESS)
+         fence_fd = -1; /* VK took ownership */
+   }
+
+   if (semaphore_fd >= 0)
+      close(semaphore_fd);
+   if (fence_fd >= 0)
+      close(fence_fd);
+
+   return result;
+}
+
+VkResult
+v3dv_QueueSignalReleaseImageANDROID(VkQueue queue,
+                                    uint32_t waitSemaphoreCount,
+                                    const VkSemaphore *pWaitSemaphores,
+                                    VkImage image,
+                                    int *pNativeFenceFd)
+{
+   VkResult result;
+
+   if (waitSemaphoreCount == 0)
+      goto done;
+
+   result = v3dv_QueueSubmit(
+      queue, 1,
+      &(VkSubmitInfo) {
+         .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
+         .waitSemaphoreCount = 1,
+         .pWaitSemaphores = pWaitSemaphores,
+         .pWaitDstStageMask =
+            &(VkPipelineStageFlags) { VK_PIPELINE_STAGE_ALL_COMMANDS_BIT },
+      },
+      (VkFence) VK_NULL_HANDLE);
+   if (result != VK_SUCCESS)
+      return result;
+
+done:
+   if (pNativeFenceFd) {
+      /* We can rely implicit on sync because above we submitted all
+       * semaphores to the queue.
+       */
+      *pNativeFenceFd = -1;
+   }
+
+   return VK_SUCCESS;
+}
diff --git a/src/broadcom/vulkan/v3dv_device.c b/src/broadcom/vulkan/v3dv_device.c
index 2ab2ccb90ac..8d17320c652 100644
--- a/src/broadcom/vulkan/v3dv_device.c
+++ b/src/broadcom/vulkan/v3dv_device.c
@@ -155,6 +155,9 @@ get_device_extensions(const struct v3dv_physical_device *device,
       .EXT_private_data                    = true,
       .EXT_provoking_vertex                = true,
       .EXT_vertex_attribute_divisor        = true,
+#ifdef ANDROID
+      .ANDROID_native_buffer               = true,
+#endif
    };
 }
 
diff --git a/src/broadcom/vulkan/v3dv_image.c b/src/broadcom/vulkan/v3dv_image.c
index 06ecb2bfa12..395a7f467fa 100644
--- a/src/broadcom/vulkan/v3dv_image.c
+++ b/src/broadcom/vulkan/v3dv_image.c
@@ -296,6 +296,27 @@ create_image(struct v3dv_device *device,
       tiling = VK_IMAGE_TILING_LINEAR;
    }
 
+#ifdef ANDROID
+   const VkNativeBufferANDROID *native_buffer =
+      vk_find_struct_const(pCreateInfo->pNext, NATIVE_BUFFER_ANDROID);
+
+   int native_buf_fd = -1;
+   int native_buf_stride = 0;
+   int native_buf_size = 0;
+
+   if (native_buffer != NULL) {
+      VkResult result = v3dv_gralloc_info(device, native_buffer, &native_buf_fd,
+                                          &native_buf_stride, &native_buf_size, &modifier);
+      if (result != VK_SUCCESS) {
+         vk_image_destroy(&device->vk, pAllocator, &image->vk);
+         return result;
+      }
+
+      if (modifier != DRM_FORMAT_MOD_BROADCOM_UIF)
+         tiling = VK_IMAGE_TILING_LINEAR;
+   }
+#endif
+
    const struct v3dv_format *format =
       v3dv_X(device, get_format)(pCreateInfo->format);
    v3dv_assert(format != NULL && format->supported);
@@ -320,6 +341,21 @@ create_image(struct v3dv_device *device,
 
    v3d_setup_slices(image);
 
+#ifdef ANDROID
+   if (native_buffer != NULL) {
+      image->slices[0].stride = native_buf_stride;
+      image->slices[0].size = image->size = native_buf_size;
+
+      VkResult result = v3dv_import_native_buffer_fd(v3dv_device_to_handle(device),
+                                                     native_buf_fd, pAllocator,
+                                                     v3dv_image_to_handle(image));
+      if (result != VK_SUCCESS) {
+         vk_object_free(&device->vk, pAllocator, image);
+         return result;
+      }
+   }
+#endif
+
    *pImage = v3dv_image_to_handle(image);
 
    return VK_SUCCESS;
@@ -435,6 +471,11 @@ v3dv_DestroyImage(VkDevice _device,
    if (image == NULL)
       return;
 
+#ifdef ANDROID
+   if (image->is_native_buffer_memory)
+      v3dv_FreeMemory(_device,  v3dv_device_memory_to_handle(image->mem), pAllocator);
+#endif
+
    vk_image_destroy(&device->vk, pAllocator, &image->vk);
 }
 
diff --git a/src/broadcom/vulkan/v3dv_private.h b/src/broadcom/vulkan/v3dv_private.h
index 9636c3f2c47..71068d52253 100644
--- a/src/broadcom/vulkan/v3dv_private.h
+++ b/src/broadcom/vulkan/v3dv_private.h
@@ -471,6 +471,15 @@ struct v3dv_device {
     */
    struct v3dv_bo *default_attribute_float;
    VkPhysicalDeviceFeatures features;
+
+#ifdef ANDROID
+   const void *gralloc;
+   enum {
+      V3DV_GRALLOC_UNKNOWN,
+      V3DV_GRALLOC_CROS,
+      V3DV_GRALLOC_OTHER,
+   } gralloc_type;
+#endif
 };
 
 struct v3dv_device_memory {
@@ -536,6 +545,11 @@ struct v3dv_image {
    struct v3dv_device_memory *mem;
    VkDeviceSize mem_offset;
    uint32_t alignment;
+
+#ifdef ANDROID
+   /* Image is backed by VK_ANDROID_native_buffer, */
+   bool is_native_buffer_memory;
+#endif
 };
 
 VkImageViewType v3dv_image_type_to_view_type(VkImageType type);
@@ -2157,4 +2171,20 @@ u64_compare(const void *key1, const void *key2)
 #  undef v3dX
 #endif
 
+#ifdef ANDROID
+VkResult
+v3dv_gralloc_info(struct v3dv_device *device,
+                  const VkNativeBufferANDROID *gralloc_info,
+                  int *out_dmabuf,
+                  int *out_stride,
+                  int *out_size,
+                  uint64_t *out_modifier);
+
+VkResult
+v3dv_import_native_buffer_fd(VkDevice device_h,
+                             int dma_buf,
+                             const VkAllocationCallbacks *alloc,
+                             VkImage image_h);
+#endif /* ANDROID */
+
 #endif /* V3DV_PRIVATE_H */



More information about the mesa-commit mailing list