anv/android: support creating images from external format
authorTapani Pälli <tapani.palli@intel.com>
Thu, 8 Nov 2018 08:37:12 +0000 (10:37 +0200)
committerTapani Pälli <tapani.palli@intel.com>
Wed, 19 Dec 2018 07:38:41 +0000 (09:38 +0200)
Since we don't know the exact format at creation time, some initialization
is done only when bound with memory in vkBindImageMemory.

v2: demand dedicated allocation in vkGetImageMemoryRequirements2 if
    image has external format

v3: refactor prepare_ahw_image, support vkBindImageMemory2,
    calculate stride correctly for rgb(x) surfaces, rename as
    'resolve_ahw_image'

v4: rebase to b43f955037c changes
v5: add some assertions to verify input correctness (Lionel)

Signed-off-by: Tapani Pälli <tapani.palli@intel.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
src/intel/vulkan/anv_android.c
src/intel/vulkan/anv_android.h
src/intel/vulkan/anv_android_stubs.c
src/intel/vulkan/anv_device.c
src/intel/vulkan/anv_image.c
src/intel/vulkan/anv_private.h

index ca1eae7be99fb475009d4baeffd924c99e311f97..1f6f1bc56e30b2bee66b9838a6e4b0bf901e4163 100644 (file)
@@ -373,6 +373,42 @@ anv_create_ahw_memory(VkDevice device_h,
    return VK_SUCCESS;
 }
 
+VkResult
+anv_image_from_external(
+   VkDevice device_h,
+   const VkImageCreateInfo *base_info,
+   const struct VkExternalMemoryImageCreateInfo *create_info,
+   const VkAllocationCallbacks *alloc,
+   VkImage *out_image_h)
+{
+   ANV_FROM_HANDLE(anv_device, device, device_h);
+
+   const struct VkExternalFormatANDROID *ext_info =
+      vk_find_struct_const(base_info->pNext, EXTERNAL_FORMAT_ANDROID);
+
+   if (ext_info && ext_info->externalFormat != 0) {
+      assert(base_info->format == VK_FORMAT_UNDEFINED);
+      assert(base_info->imageType == VK_IMAGE_TYPE_2D);
+      assert(base_info->usage == VK_IMAGE_USAGE_SAMPLED_BIT);
+      assert(base_info->tiling == VK_IMAGE_TILING_OPTIMAL);
+   }
+
+   struct anv_image_create_info anv_info = {
+      .vk_info = base_info,
+      .isl_extra_usage_flags = ISL_SURF_USAGE_DISABLE_AUX_BIT,
+      .external_format = true,
+   };
+
+   VkImage image_h;
+   VkResult result = anv_image_create(device_h, &anv_info, alloc, &image_h);
+   if (result != VK_SUCCESS)
+      return result;
+
+   *out_image_h = image_h;
+
+   return VK_SUCCESS;
+}
+
 VkResult
 anv_image_from_gralloc(VkDevice device_h,
                        const VkImageCreateInfo *base_info,
index 01f0e856291b2b4435f4a177c90f317ce3033cce..d5c073126e3817d8decf2f5124c0da3329a0effd 100644 (file)
@@ -29,6 +29,8 @@
 #include <vulkan/vk_android_native_buffer.h>
 
 struct anv_device_memory;
+struct anv_device;
+struct anv_image;
 
 VkResult anv_image_from_gralloc(VkDevice device_h,
                                 const VkImageCreateInfo *base_info,
@@ -36,6 +38,12 @@ VkResult anv_image_from_gralloc(VkDevice device_h,
                                 const VkAllocationCallbacks *alloc,
                                 VkImage *pImage);
 
+VkResult anv_image_from_external(VkDevice device_h,
+                                 const VkImageCreateInfo *base_info,
+                                 const struct VkExternalMemoryImageCreateInfo *create_info,
+                                 const VkAllocationCallbacks *alloc,
+                                 VkImage *out_image_h);
+
 uint64_t anv_ahw_usage_from_vk_usage(const VkImageCreateFlags vk_create,
                                      const VkImageUsageFlags vk_usage);
 
index ccc16500494b5a02c2934f097648af6ed8816459..a34afc198a1e20ca80a078fb615966f49cf9b75b 100644 (file)
@@ -55,3 +55,13 @@ anv_create_ahw_memory(VkDevice device_h,
 {
    return VK_ERROR_EXTENSION_NOT_PRESENT;
 }
+
+VkResult
+anv_image_from_external(VkDevice device_h,
+                        const VkImageCreateInfo *base_info,
+                        const struct VkExternalMemoryImageCreateInfo *create_info,
+                        const VkAllocationCallbacks *alloc,
+                        VkImage *out_image_h)
+{
+   return VK_ERROR_EXTENSION_NOT_PRESENT;
+}
index fa3a8a417b98de69dbd8612b4c67076f0fbd0ab7..2a3919d2949f040a9b0d298be36bf5cf4658973e 100644 (file)
@@ -2712,6 +2712,12 @@ void anv_GetImageMemoryRequirements(
     */
    uint32_t memory_types = (1ull << pdevice->memory.type_count) - 1;
 
+   /* We must have image allocated or imported at this point. According to the
+    * specification, external images must have been bound to memory before
+    * calling GetImageMemoryRequirements.
+    */
+   assert(image->size > 0);
+
    pMemoryRequirements->size = image->size;
    pMemoryRequirements->alignment = image->alignment;
    pMemoryRequirements->memoryTypeBits = memory_types;
@@ -2752,6 +2758,12 @@ void anv_GetImageMemoryRequirements2(
          pMemoryRequirements->memoryRequirements.memoryTypeBits =
                (1ull << pdevice->memory.type_count) - 1;
 
+         /* We must have image allocated or imported at this point. According to the
+          * specification, external images must have been bound to memory before
+          * calling GetImageMemoryRequirements.
+          */
+         assert(image->planes[plane].size > 0);
+
          pMemoryRequirements->memoryRequirements.size = image->planes[plane].size;
          pMemoryRequirements->memoryRequirements.alignment =
             image->planes[plane].alignment;
@@ -2768,7 +2780,7 @@ void anv_GetImageMemoryRequirements2(
       switch (ext->sType) {
       case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS: {
          VkMemoryDedicatedRequirements *requirements = (void *)ext;
-         if (image->needs_set_tiling) {
+         if (image->needs_set_tiling || image->external_format) {
             /* If we need to set the tiling for external consumers, we need a
              * dedicated allocation.
              *
index a9458a2185c316aff342c25fe852cb29fec9ce6b..1355d9543cde85e878a352ca64905ebcbbb560c3 100644 (file)
@@ -594,6 +594,15 @@ anv_image_create(VkDevice _device,
    image->drm_format_mod = isl_mod_info ? isl_mod_info->modifier :
                                           DRM_FORMAT_MOD_INVALID;
 
+   /* In case of external format, We don't know format yet,
+    * so skip the rest for now.
+    */
+   if (create_info->external_format) {
+      image->external_format = true;
+      *pImage = anv_image_to_handle(image);
+      return VK_SUCCESS;
+   }
+
    const struct anv_format *format = anv_get_format(image->vk_format);
    assert(format != NULL);
 
@@ -635,9 +644,16 @@ anv_CreateImage(VkDevice device,
                 const VkAllocationCallbacks *pAllocator,
                 VkImage *pImage)
 {
+   const struct VkExternalMemoryImageCreateInfo *create_info =
+      vk_find_struct_const(pCreateInfo->pNext, EXTERNAL_MEMORY_IMAGE_CREATE_INFO);
+
+   if (create_info && (create_info->handleTypes &
+       VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID))
+      return anv_image_from_external(device, pCreateInfo, create_info,
+                                     pAllocator, pImage);
+
    const VkNativeBufferANDROID *gralloc_info =
       vk_find_struct_const(pCreateInfo->pNext, NATIVE_BUFFER_ANDROID);
-
    if (gralloc_info)
       return anv_image_from_gralloc(device, pCreateInfo, gralloc_info,
                                     pAllocator, pImage);
@@ -690,6 +706,83 @@ static void anv_image_bind_memory_plane(struct anv_device *device,
    };
 }
 
+/* We are binding AHardwareBuffer. Get a description, resolve the
+ * format and prepare anv_image properly.
+ */
+static void
+resolve_ahw_image(struct anv_device *device,
+                  struct anv_image *image,
+                  struct anv_device_memory *mem)
+{
+#ifdef ANDROID
+   assert(mem->ahw);
+   AHardwareBuffer_Desc desc;
+   AHardwareBuffer_describe(mem->ahw, &desc);
+
+   /* Check tiling. */
+   int i915_tiling = anv_gem_get_tiling(device, mem->bo->gem_handle);
+   VkImageTiling vk_tiling;
+   isl_tiling_flags_t isl_tiling_flags = 0;
+
+   switch (i915_tiling) {
+   case I915_TILING_NONE:
+      vk_tiling = VK_IMAGE_TILING_LINEAR;
+      isl_tiling_flags = ISL_TILING_LINEAR_BIT;
+      break;
+   case I915_TILING_X:
+      vk_tiling = VK_IMAGE_TILING_OPTIMAL;
+      isl_tiling_flags = ISL_TILING_X_BIT;
+      break;
+   case I915_TILING_Y:
+      vk_tiling = VK_IMAGE_TILING_OPTIMAL;
+      isl_tiling_flags = ISL_TILING_Y0_BIT;
+      break;
+   case -1:
+   default:
+      unreachable("Invalid tiling flags.");
+   }
+
+   assert(vk_tiling == VK_IMAGE_TILING_LINEAR ||
+          vk_tiling == VK_IMAGE_TILING_OPTIMAL);
+
+   /* Check format. */
+   VkFormat vk_format = vk_format_from_android(desc.format);
+   enum isl_format isl_fmt = anv_get_isl_format(&device->info,
+                                                vk_format,
+                                                VK_IMAGE_ASPECT_COLOR_BIT,
+                                                vk_tiling);
+   assert(format != ISL_FORMAT_UNSUPPORTED);
+
+   /* Handle RGB(X)->RGBA fallback. */
+   switch (desc.format) {
+   case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
+   case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
+      if (isl_format_is_rgb(isl_fmt))
+         isl_fmt = isl_format_rgb_to_rgba(isl_fmt);
+      break;
+   }
+
+   /* Now we are able to fill anv_image fields properly and create
+    * isl_surface for it.
+    */
+   image->vk_format = vk_format;
+   image->format = anv_get_format(vk_format);
+   image->aspects = vk_format_aspects(image->vk_format);
+   image->n_planes = image->format->n_planes;
+   image->ccs_e_compatible = false;
+
+   uint32_t stride = desc.stride *
+                     (isl_format_get_layout(isl_fmt)->bpb / 8);
+
+   uint32_t b;
+   for_each_bit(b, image->aspects) {
+      VkResult r = make_surface(device, image, stride, isl_tiling_flags,
+                                ISL_SURF_USAGE_DISABLE_AUX_BIT, (1 << b));
+      assert(r == VK_SUCCESS);
+   }
+#endif
+}
+
 VkResult anv_BindImageMemory(
     VkDevice                                    _device,
     VkImage                                     _image,
@@ -700,6 +793,9 @@ VkResult anv_BindImageMemory(
    ANV_FROM_HANDLE(anv_device_memory, mem, _memory);
    ANV_FROM_HANDLE(anv_image, image, _image);
 
+   if (mem->ahw)
+      resolve_ahw_image(device, image, mem);
+
    uint32_t aspect_bit;
    anv_foreach_image_aspect_bit(aspect_bit, image, image->aspects) {
       uint32_t plane =
@@ -721,8 +817,11 @@ VkResult anv_BindImageMemory2(
       const VkBindImageMemoryInfo *bind_info = &pBindInfos[i];
       ANV_FROM_HANDLE(anv_device_memory, mem, bind_info->memory);
       ANV_FROM_HANDLE(anv_image, image, bind_info->image);
-      VkImageAspectFlags aspects = image->aspects;
 
+      if (mem->ahw)
+         resolve_ahw_image(device, image, mem);
+
+      VkImageAspectFlags aspects = image->aspects;
       vk_foreach_struct_const(s, bind_info->pNext) {
          switch (s->sType) {
          case VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO: {
index bfd1482ef8dbb08dc03f1cf24db5c1c2db03ee22..cd24714f93e6b35ba16a2d8efe50d980cab46a8b 100644 (file)
@@ -2699,6 +2699,9 @@ struct anv_image {
     */
    bool ccs_e_compatible;
 
+   /* Image was created with external format. */
+   bool external_format;
+
    /**
     * Image subsurfaces
     *
@@ -3073,6 +3076,7 @@ struct anv_image_create_info {
    isl_surf_usage_flags_t isl_extra_usage_flags;
 
    uint32_t stride;
+   bool external_format;
 };
 
 VkResult anv_image_create(VkDevice _device,