[vulkan] Add AHB support functions

bug: 122080810

This CL adds support functions for use with AHardwareBuffer
for getting buffer info and
acquiring/importing/creating buffers.

This is inspired by / based on Intel ANV
https://github.com/mesa3d/mesa/blob/master/src/intel/vulkan/anv_android.c

which has a similar layering between implementation-specific Vulkan
and AHardwareBuffer.

No new entry points are exposed yet.

Test: Builds

Change-Id: Ieb5bfcb8b65b87650cd4a2658668efac99f9105c
diff --git a/system/vulkan_enc/Android.mk b/system/vulkan_enc/Android.mk
index efa2799..d59336f 100644
--- a/system/vulkan_enc/Android.mk
+++ b/system/vulkan_enc/Android.mk
@@ -42,7 +42,8 @@
     -DVK_USE_PLATFORM_ANDROID_KHR \
     -DVK_NO_PROTOTYPES \
 
-LOCAL_SRC_FILES := HostVisibleMemoryVirtualization.cpp \
+LOCAL_SRC_FILES := AndroidHardwareBuffer.cpp \
+    HostVisibleMemoryVirtualization.cpp \
     Resources.cpp \
     Validation.cpp \
     VulkanStream.cpp \
@@ -57,6 +58,7 @@
 
 
 ifeq (true,$(GOLDFISH_OPENGL_BUILD_FOR_HOST))
+LOCAL_CFLAGS += -D__ANDROID_API__=28
 $(call emugl-export,SHARED_LIBRARIES,libgui)
 else
 $(call emugl-export,SHARED_LIBRARIES,libsync libnativewindow)
diff --git a/system/vulkan_enc/AndroidHardwareBuffer.cpp b/system/vulkan_enc/AndroidHardwareBuffer.cpp
new file mode 100644
index 0000000..70ff6cc
--- /dev/null
+++ b/system/vulkan_enc/AndroidHardwareBuffer.cpp
@@ -0,0 +1,242 @@
+/// Copyright (C) 2019 The Android Open Source Project
+// Copyright (C) 2019 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include "AndroidHardwareBuffer.h"
+
+#include "Resources.h"
+
+#include "gralloc_cb.h"
+#include "vk_format_info.h"
+
+namespace goldfish_vk {
+
+// From Intel ANV implementation.
+/* Construct ahw usage mask from image usage bits, see
+ * 'AHardwareBuffer Usage Equivalence' in Vulkan spec.
+ */
+static uint64_t
+goldfish_ahw_usage_from_vk_usage(const VkImageCreateFlags vk_create,
+                                 const VkImageUsageFlags vk_usage)
+{
+   uint64_t ahw_usage = 0;
+
+   if (vk_usage & VK_IMAGE_USAGE_SAMPLED_BIT)
+      ahw_usage |= AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
+
+   if (vk_usage & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT)
+      ahw_usage |= AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
+
+   if (vk_usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
+      ahw_usage |= AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT;
+
+   if (vk_create & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT)
+      ahw_usage |= AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP;
+
+   if (vk_create & VK_IMAGE_CREATE_PROTECTED_BIT)
+      ahw_usage |= AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT;
+
+   /* No usage bits set - set at least one GPU usage. */
+   if (ahw_usage == 0)
+      ahw_usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
+
+   return ahw_usage;
+}
+
+VkResult getAndroidHardwareBufferPropertiesANDROID(
+    const HostVisibleMemoryVirtualizationInfo* hostMemVirtInfo,
+    VkDevice,
+    const AHardwareBuffer* buffer,
+    VkAndroidHardwareBufferPropertiesANDROID* pProperties) {
+
+    VkAndroidHardwareBufferFormatPropertiesANDROID* ahbFormatProps =
+        (VkAndroidHardwareBufferFormatPropertiesANDROID*)vk_find_struct(
+            (vk_struct*)pProperties->pNext,
+            VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID);
+
+    if (ahbFormatProps) {
+        AHardwareBuffer_Desc desc;
+        AHardwareBuffer_describe(buffer, &desc);
+
+       uint64_t gpu_usage =
+          AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
+          AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT |
+          AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER;
+
+        if (!(desc.usage & (gpu_usage))) {
+            return VK_ERROR_INVALID_EXTERNAL_HANDLE;
+        }
+
+        ahbFormatProps->format =
+            vk_format_from_android(desc.format);
+
+        // Just don't, for now
+        ahbFormatProps->externalFormat = 0;
+
+        // The formatFeatures member must include
+        // VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT and at least one of
+        // VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT or
+        // VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT, and should include
+        // VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT and
+        // VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT.
+
+        ahbFormatProps->formatFeatures =
+            VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT |
+            VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT;
+
+        // "Implementations may not always be able to determine the color model,
+        // numerical range, or chroma offsets of the image contents, so the values in
+        // VkAndroidHardwareBufferFormatPropertiesANDROID are only suggestions.
+        // Applications should treat these values as sensible defaults to use in the
+        // absence of more reliable information obtained through some other means."
+
+        ahbFormatProps->samplerYcbcrConversionComponents.r = VK_COMPONENT_SWIZZLE_IDENTITY;
+        ahbFormatProps->samplerYcbcrConversionComponents.g = VK_COMPONENT_SWIZZLE_IDENTITY;
+        ahbFormatProps->samplerYcbcrConversionComponents.b = VK_COMPONENT_SWIZZLE_IDENTITY;
+        ahbFormatProps->samplerYcbcrConversionComponents.a = VK_COMPONENT_SWIZZLE_IDENTITY;
+
+        ahbFormatProps->suggestedYcbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601;
+        ahbFormatProps->suggestedYcbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_FULL;
+
+        ahbFormatProps->suggestedXChromaOffset = VK_CHROMA_LOCATION_MIDPOINT;
+        ahbFormatProps->suggestedYChromaOffset = VK_CHROMA_LOCATION_MIDPOINT;
+    }
+
+    const native_handle_t *handle =
+       AHardwareBuffer_getNativeHandle(buffer);
+    const cb_handle_t* cb_handle =
+        reinterpret_cast<const cb_handle_t*>(handle);
+    uint32_t colorBufferHandle = cb_handle->hostHandle;
+
+    if (!colorBufferHandle) {
+        return VK_ERROR_INVALID_EXTERNAL_HANDLE;
+    }
+
+    // Disallow host visible heaps for now
+    // (hard to make actual dedicated allocs)
+    uint32_t memoryTypeBits = 0;
+    for (uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; ++i) {
+        memoryTypeBits |=
+            (!isHostVisibleMemoryTypeIndexForGuest(
+             hostMemVirtInfo, i)) << i;
+    }
+
+    pProperties->memoryTypeBits = memoryTypeBits;
+    pProperties->allocationSize =
+        cb_handle->ashmemBase ? cb_handle->ashmemSize : 0;
+
+    return VK_SUCCESS;
+}
+
+// Based on Intel ANV implementation.
+VkResult getMemoryAndroidHardwareBufferANDROID(struct AHardwareBuffer **pBuffer) {
+
+   /* Some quotes from Vulkan spec:
+    *
+    * "If the device memory was created by importing an Android hardware
+    * buffer, vkGetMemoryAndroidHardwareBufferANDROID must return that same
+    * Android hardware buffer object."
+    *
+    * "VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID must
+    * have been included in VkExportMemoryAllocateInfo::handleTypes when
+    * memory was created."
+    */
+
+    if (!pBuffer) return VK_ERROR_OUT_OF_HOST_MEMORY;
+    if (!(*pBuffer)) return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+    AHardwareBuffer_acquire(*pBuffer);
+    return VK_SUCCESS;
+}
+
+VkResult importAndroidHardwareBuffer(
+    const VkImportAndroidHardwareBufferInfoANDROID* info,
+    struct AHardwareBuffer **importOut) {
+
+    if (!info || !info->buffer) {
+        return VK_ERROR_INVALID_EXTERNAL_HANDLE;
+    }
+
+    const native_handle_t *handle =
+       AHardwareBuffer_getNativeHandle(info->buffer);
+    const cb_handle_t* cb_handle =
+        reinterpret_cast<const cb_handle_t*>(handle);
+    uint32_t colorBufferHandle = cb_handle->hostHandle;
+
+    if (!colorBufferHandle) {
+        return VK_ERROR_INVALID_EXTERNAL_HANDLE;
+    }
+
+    auto ahb = info->buffer;
+
+    AHardwareBuffer_acquire(ahb);
+    *importOut = ahb;
+    return VK_SUCCESS;
+}
+
+VkResult createAndroidHardwareBuffer(
+    bool hasDedicatedImage,
+    bool hasDedicatedBuffer,
+    const VkExtent3D& imageExtent,
+    uint32_t imageLayers,
+    VkFormat imageFormat,
+    VkImageUsageFlags imageUsage,
+    VkImageCreateFlags imageCreateFlags,
+    VkDeviceSize bufferSize,
+    VkDeviceSize allocationInfoAllocSize,
+    struct AHardwareBuffer **out) {
+
+    uint32_t w = 0;
+    uint32_t h = 1;
+    uint32_t layers = 1;
+    uint32_t format = 0;
+    uint64_t usage = 0;
+
+    /* If caller passed dedicated information. */
+    if (hasDedicatedImage) {
+       w = imageExtent.width;
+       h = imageExtent.height;
+       layers = imageLayers;
+       format = android_format_from_vk(imageFormat);
+       usage = goldfish_ahw_usage_from_vk_usage(imageCreateFlags, imageUsage);
+    } else if (hasDedicatedBuffer) {
+       w = bufferSize;
+       format = AHARDWAREBUFFER_FORMAT_BLOB;
+       usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
+               AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
+    } else {
+       w = allocationInfoAllocSize;
+       format = AHARDWAREBUFFER_FORMAT_BLOB;
+       usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
+               AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
+    }
+
+    struct AHardwareBuffer *ahw = NULL;
+    struct AHardwareBuffer_Desc desc = {
+        .width = w,
+        .height = h,
+        .layers = layers,
+        .format = format,
+        .usage = usage,
+    };
+
+    if (AHardwareBuffer_allocate(&desc, &ahw) != 0) {
+        return VK_ERROR_OUT_OF_HOST_MEMORY;
+    }
+
+    *out = ahw;
+
+    return VK_SUCCESS;
+}
+
+} // namespace goldfish_vk
\ No newline at end of file
diff --git a/system/vulkan_enc/AndroidHardwareBuffer.h b/system/vulkan_enc/AndroidHardwareBuffer.h
new file mode 100644
index 0000000..fc6a27e
--- /dev/null
+++ b/system/vulkan_enc/AndroidHardwareBuffer.h
@@ -0,0 +1,52 @@
+/// Copyright (C) 2019 The Android Open Source Project
+// Copyright (C) 2019 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#pragma once
+
+#include "HostVisibleMemoryVirtualization.h"
+
+#include <vulkan/vulkan.h>
+#include <vndk/hardware_buffer.h>
+
+// Structure similar to
+// https://github.com/mesa3d/mesa/blob/master/src/intel/vulkan/anv_android.c
+
+namespace goldfish_vk {
+
+VkResult getAndroidHardwareBufferPropertiesANDROID(
+    const HostVisibleMemoryVirtualizationInfo* hostMemVirtInfo,
+    VkDevice device,
+    const AHardwareBuffer* buffer,
+    VkAndroidHardwareBufferPropertiesANDROID* pProperties);
+
+VkResult getMemoryAndroidHardwareBufferANDROID(
+    struct AHardwareBuffer **pBuffer);
+
+VkResult importAndroidHardwareBuffer(
+    const VkImportAndroidHardwareBufferInfoANDROID* info,
+    struct AHardwareBuffer **importOut);
+
+VkResult createAndroidHardwareBuffer(
+    bool hasDedicatedImage,
+    bool hasDedicatedBuffer,
+    const VkExtent3D& imageExtent,
+    uint32_t imageLayers,
+    VkFormat imageFormat,
+    VkImageUsageFlags imageUsage,
+    VkImageCreateFlags imageCreateFlags,
+    VkDeviceSize bufferSize,
+    VkDeviceSize allocationInfoAllocSize,
+    struct AHardwareBuffer **out);
+
+} // namespace goldfish_vk
\ No newline at end of file
diff --git a/system/vulkan_enc/CMakeLists.txt b/system/vulkan_enc/CMakeLists.txt
index 20c5d40..3b91d56 100644
--- a/system/vulkan_enc/CMakeLists.txt
+++ b/system/vulkan_enc/CMakeLists.txt
@@ -1,10 +1,10 @@
 # This is an autogenerated file! Do not edit!
 # instead run make from .../device/generic/goldfish-opengl
 # which will re-generate this file.
-android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/system/vulkan_enc/Android.mk" "f2375abceb5cd867632f063c8cd8234c2cce414d155831a2c851bd7c2607416c")
-set(vulkan_enc_src HostVisibleMemoryVirtualization.cpp Resources.cpp Validation.cpp VulkanStream.cpp VulkanHandleMapping.cpp ResourceTracker.cpp VkEncoder.cpp goldfish_vk_extension_structs_guest.cpp goldfish_vk_marshaling_guest.cpp goldfish_vk_deepcopy_guest.cpp goldfish_vk_handlemap_guest.cpp goldfish_vk_transform_guest.cpp)
+android_validate_sha256("${GOLDFISH_DEVICE_ROOT}/system/vulkan_enc/Android.mk" "8d27c26a3f061872b902d8c89030638903e53faf8467a9e17c13580e71a86452")
+set(vulkan_enc_src AndroidHardwareBuffer.cpp HostVisibleMemoryVirtualization.cpp Resources.cpp Validation.cpp VulkanStream.cpp VulkanHandleMapping.cpp ResourceTracker.cpp VkEncoder.cpp goldfish_vk_extension_structs_guest.cpp goldfish_vk_marshaling_guest.cpp goldfish_vk_deepcopy_guest.cpp goldfish_vk_handlemap_guest.cpp goldfish_vk_transform_guest.cpp)
 android_add_shared_library(vulkan_enc)
 target_include_directories(vulkan_enc PRIVATE ${GOLDFISH_DEVICE_ROOT}/android-emu ${GOLDFISH_DEVICE_ROOT}/shared/OpenglCodecCommon ${GOLDFISH_DEVICE_ROOT}/system/vulkan_enc ${GOLDFISH_DEVICE_ROOT}/./host/include/libOpenglRender ${GOLDFISH_DEVICE_ROOT}/./system/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/guest ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/host/include ${GOLDFISH_DEVICE_ROOT}/./../../../external/qemu/android/android-emugl/host/include/vulkan)
-target_compile_definitions(vulkan_enc PRIVATE "-DWITH_GLES2" "-DPLATFORM_SDK_VERSION=29" "-DGOLDFISH_HIDL_GRALLOC" "-DEMULATOR_OPENGL_POST_O=1" "-DHOST_BUILD" "-DANDROID" "-DGL_GLEXT_PROTOTYPES" "-DPAGE_SIZE=4096" "-DGOLDFISH_VULKAN" "-DLOG_TAG=\"goldfish_vulkan\"" "-DVK_ANDROID_native_buffer" "-DVK_GOOGLE_address_space" "-DVK_USE_PLATFORM_ANDROID_KHR" "-DVK_NO_PROTOTYPES")
+target_compile_definitions(vulkan_enc PRIVATE "-DWITH_GLES2" "-DPLATFORM_SDK_VERSION=29" "-DGOLDFISH_HIDL_GRALLOC" "-DEMULATOR_OPENGL_POST_O=1" "-DHOST_BUILD" "-DANDROID" "-DGL_GLEXT_PROTOTYPES" "-DPAGE_SIZE=4096" "-DGOLDFISH_VULKAN" "-DLOG_TAG=\"goldfish_vulkan\"" "-DVK_ANDROID_native_buffer" "-DVK_GOOGLE_address_space" "-DVK_USE_PLATFORM_ANDROID_KHR" "-DVK_NO_PROTOTYPES" "-D__ANDROID_API__=28")
 target_compile_options(vulkan_enc PRIVATE "-fvisibility=default" "-Wno-missing-field-initializers" "-Werror" "-fstrict-aliasing")
 target_link_libraries(vulkan_enc PRIVATE gui cutils utils log OpenglCodecCommon_host android-emu-shared)
\ No newline at end of file
diff --git a/system/vulkan_enc/HostVisibleMemoryVirtualization.h b/system/vulkan_enc/HostVisibleMemoryVirtualization.h
index 10afc46..30ab2f6 100644
--- a/system/vulkan_enc/HostVisibleMemoryVirtualization.h
+++ b/system/vulkan_enc/HostVisibleMemoryVirtualization.h
@@ -109,4 +109,4 @@
 
 void subFreeHostMemory(SubAlloc* toFree);
 
-} // namespace goldfish_vk
+} // namespace goldfish_vk
\ No newline at end of file
diff --git a/system/vulkan_enc/ResourceTracker.cpp b/system/vulkan_enc/ResourceTracker.cpp
index 980f4bf..df75721 100644
--- a/system/vulkan_enc/ResourceTracker.cpp
+++ b/system/vulkan_enc/ResourceTracker.cpp
@@ -16,6 +16,7 @@
 #include "ResourceTracker.h"
 
 #include "../OpenglSystemCommon/EmulatorFeatureInfo.h"
+#include "AndroidHardwareBuffer.h"
 #include "HostVisibleMemoryVirtualization.h"
 #include "Resources.h"
 #include "VkEncoder.h"
@@ -139,6 +140,7 @@
         GoldfishAddressSpaceBlock*
             goldfishAddressSpaceBlock = nullptr;
         SubAlloc subAlloc;
+        AHardwareBuffer** ahbHandle = nullptr;
     };
 
 #define HANDLE_REGISTER_IMPL_IMPL(type) \
@@ -694,6 +696,49 @@
         }
     }
 
+    VkResult on_vkGetAndroidHardwareBufferPropertiesANDROID(
+        VkDevice device,
+        const AHardwareBuffer* buffer,
+        VkAndroidHardwareBufferPropertiesANDROID* pProperties) {
+        return getAndroidHardwareBufferPropertiesANDROID(
+            &mHostVisibleMemoryVirtInfo,
+            device, buffer, pProperties);
+    }
+
+    VkResult on_vkGetMemoryAndroidHardwareBufferANDROID(
+        VkDevice device,
+        const VkMemoryGetAndroidHardwareBufferInfoANDROID *pInfo,
+        struct AHardwareBuffer** pBuffer) {
+
+        if (!pInfo) return VK_ERROR_INITIALIZATION_FAILED;
+        if (!pInfo->memory) return VK_ERROR_INITIALIZATION_FAILED;
+
+        AutoLock lock(mLock);
+
+        auto deviceIt = info_VkDevice.find(device);
+
+        if (deviceIt == info_VkDevice.end()) {
+            return VK_ERROR_INITIALIZATION_FAILED;
+        }
+
+        auto memoryIt = info_VkDeviceMemory.find(pInfo->memory);
+
+        if (memoryIt == info_VkDeviceMemory.end()) {
+            return VK_ERROR_INITIALIZATION_FAILED;
+        }
+
+        auto& info = memoryIt->second;
+
+        VkResult queryRes =
+            getMemoryAndroidHardwareBufferANDROID(info.ahbHandle);
+
+        if (queryRes != VK_SUCCESS) return queryRes;
+
+        *pBuffer = *(info.ahbHandle);
+
+        return queryRes;
+    }
+
     VkResult on_vkAllocateMemory(
         void* context,
         VkResult input_result,
diff --git a/system/vulkan_enc/Resources.h b/system/vulkan_enc/Resources.h
index 0948df6..0726aac 100644
--- a/system/vulkan_enc/Resources.h
+++ b/system/vulkan_enc/Resources.h
@@ -72,4 +72,18 @@
 GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES(GOLDFISH_VK_GET_HOST_U64_DECL)
 GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES(GOLDFISH_VK_DEFINE_TRIVIAL_NON_DISPATCHABLE_HANDLE_STRUCT)
 
+// From vkd3d: utility function to search for extension structs
+struct vk_struct { 
+    VkStructureType sType; 
+    struct vk_struct *pNext; 
+}; 
+ 
+static const void *vk_find_struct(struct vk_struct *chain, VkStructureType type) { 
+    while (chain) { 
+        if (chain->sType == type) return chain; 
+        chain = chain->pNext; 
+    } 
+    return nullptr; 
+} 
+
 } // extern "C"
diff --git a/system/vulkan_enc/vk_format_info.h b/system/vulkan_enc/vk_format_info.h
new file mode 100644
index 0000000..c0548a0
--- /dev/null
+++ b/system/vulkan_enc/vk_format_info.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright © 2016 Intel Corporation
+ * Copyright © 2019 The Android Open Source Project
+ * Copyright © 2019 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.
+ */
+
+#ifndef VK_FORMAT_INFO_H
+#define VK_FORMAT_INFO_H
+
+#include <stdbool.h>
+#include <vulkan/vulkan.h>
+#include <vndk/hardware_buffer.h>
+
+/* See i915_private_android_types.h in minigbm. */
+#define HAL_PIXEL_FORMAT_NV12_Y_TILED_INTEL 0x100
+
+static inline VkFormat
+vk_format_from_android(unsigned android_format)
+{
+   switch (android_format) {
+   case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
+      return VK_FORMAT_R8G8B8A8_UNORM;
+   case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
+   case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
+      return VK_FORMAT_R8G8B8_UNORM;
+   case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
+      return VK_FORMAT_R5G6B5_UNORM_PACK16;
+   case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
+      return VK_FORMAT_R16G16B16A16_SFLOAT;
+   case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
+      return VK_FORMAT_A2B10G10R10_UNORM_PACK32;
+   case HAL_PIXEL_FORMAT_NV12_Y_TILED_INTEL:
+      return VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
+   case AHARDWAREBUFFER_FORMAT_BLOB:
+   default:
+      return VK_FORMAT_UNDEFINED;
+   }
+}
+
+static inline unsigned
+android_format_from_vk(unsigned vk_format)
+{
+   switch (vk_format) {
+   case VK_FORMAT_R8G8B8A8_UNORM:
+      return AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
+   case VK_FORMAT_R8G8B8_UNORM:
+      return AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM;
+   case VK_FORMAT_R5G6B5_UNORM_PACK16:
+      return AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
+   case VK_FORMAT_R16G16B16A16_SFLOAT:
+      return AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT;
+   case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
+      return AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM;
+   case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
+      return HAL_PIXEL_FORMAT_NV12_Y_TILED_INTEL;
+   default:
+      return AHARDWAREBUFFER_FORMAT_BLOB;
+   }
+}
+
+static inline VkImageAspectFlags
+vk_format_aspects(VkFormat format)
+{
+   switch (format) {
+   case VK_FORMAT_UNDEFINED:
+      return 0;
+
+   case VK_FORMAT_S8_UINT:
+      return VK_IMAGE_ASPECT_STENCIL_BIT;
+
+   case VK_FORMAT_D16_UNORM_S8_UINT:
+   case VK_FORMAT_D24_UNORM_S8_UINT:
+   case VK_FORMAT_D32_SFLOAT_S8_UINT:
+      return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
+
+   case VK_FORMAT_D16_UNORM:
+   case VK_FORMAT_X8_D24_UNORM_PACK32:
+   case VK_FORMAT_D32_SFLOAT:
+      return VK_IMAGE_ASPECT_DEPTH_BIT;
+
+   case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
+   case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
+   case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
+   case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
+   case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
+   case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
+   case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
+   case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
+   case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
+   case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
+   case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
+   case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
+      return (VK_IMAGE_ASPECT_PLANE_0_BIT |
+              VK_IMAGE_ASPECT_PLANE_1_BIT |
+              VK_IMAGE_ASPECT_PLANE_2_BIT);
+
+   case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
+   case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
+   case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
+   case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
+   case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
+   case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
+   case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
+   case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
+      return (VK_IMAGE_ASPECT_PLANE_0_BIT |
+              VK_IMAGE_ASPECT_PLANE_1_BIT);
+
+   default:
+      return VK_IMAGE_ASPECT_COLOR_BIT;
+   }
+}
+
+static inline bool
+vk_format_is_color(VkFormat format)
+{
+   return vk_format_aspects(format) == VK_IMAGE_ASPECT_COLOR_BIT;
+}
+
+static inline bool
+vk_format_is_depth_or_stencil(VkFormat format)
+{
+   const VkImageAspectFlags aspects = vk_format_aspects(format);
+   return aspects & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT);
+}
+
+static inline bool
+vk_format_has_depth(VkFormat format)
+{
+   const VkImageAspectFlags aspects = vk_format_aspects(format);
+   return aspects & VK_IMAGE_ASPECT_DEPTH_BIT;
+}
+
+#endif /* VK_FORMAT_INFO_H */
\ No newline at end of file