[vulkan] Skeleton code for handling external guest memory

bug: 122080810

This adds the ability for ResourceTracker in the guest to
track both AHardwareBuffer's and Fuchsia vmo_handles.

Prototype code is added for AHardwareBuffer import, but not tested yet.

Change-Id: I41a74d300e341419092e95179812ce1862c8deff
diff --git a/system/vulkan_enc/ResourceTracker.cpp b/system/vulkan_enc/ResourceTracker.cpp
index ef62678..1ccad27 100644
--- a/system/vulkan_enc/ResourceTracker.cpp
+++ b/system/vulkan_enc/ResourceTracker.cpp
@@ -16,7 +16,30 @@
 #include "ResourceTracker.h"
 
 #include "../OpenglSystemCommon/EmulatorFeatureInfo.h"
+
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+
+typedef uint32_t zx_handle_t;
+#define ZX_HANDLE_INVALID         ((zx_handle_t)0)
+void zx_handle_close(zx_handle_t) { }
+
 #include "AndroidHardwareBuffer.h"
+
+#endif // VK_USE_PLATFORM_ANDROID_KHR
+
+#ifdef VK_USE_PLATFORM_FUCHSIA
+
+typedef uint32_t AHardwareBuffer;
+void AHardwareBuffer_release(AHardwareBuffer*) { }
+
+#include <fuchsia/hardware/goldfish/c/fidl.h>
+#include <lib/fzl/fdio.h>
+#include <zircon/process.h>
+#include <zircon/syscalls.h>
+#include <zircon/syscalls/object.h>
+
+#endif // VK_USE_PLATFORM_FUCHSIA
+
 #include "HostVisibleMemoryVirtualization.h"
 #include "Resources.h"
 #include "VkEncoder.h"
@@ -56,6 +79,36 @@
 
 namespace goldfish_vk {
 
+namespace {
+
+template<typename T>
+bool GetImportHandle(const void* pNext, VkStructureType import_type,
+                     uint32_t bit, uint32_t* pHandle) {
+    while (pNext) {
+        auto info = static_cast<const T*>(pNext);
+        if (info->sType == import_type && info->handleType & bit) {
+            *pHandle = info->handle;
+            return true;
+        }
+        pNext = info->pNext;
+    }
+    return false;
+}
+
+template<typename T>
+bool HasExportBit(const void* pNext, VkStructureType export_type, uint32_t bit) {
+    while (pNext) {
+        auto info = static_cast<const T*>(pNext);
+        if (info->sType == export_type && info->handleTypes & bit) {
+            return true;
+        }
+        pNext = info->pNext;
+    }
+    return false;
+}
+
+} // namespace
+
 #define MAKE_HANDLE_MAPPING_FOREACH(type_name, map_impl, map_to_u64_impl, map_from_u64_impl) \
     void mapHandles_##type_name(type_name* handles, size_t count) override { \
         for (size_t i = 0; i < count; ++i) { \
@@ -143,7 +196,8 @@
         GoldfishAddressSpaceBlock*
             goldfishAddressSpaceBlock = nullptr;
         SubAlloc subAlloc;
-        AHardwareBuffer** ahbHandle = nullptr;
+        AHardwareBuffer* ahw = nullptr;
+        zx_handle_t vmoHandle = ZX_HANDLE_INVALID;
     };
 
     // custom guest-side structs for images/buffers because of AHardwareBuffer :((
@@ -207,6 +261,14 @@
 
         auto& memInfo = it->second;
 
+        if (memInfo.ahw) {
+            AHardwareBuffer_release(memInfo.ahw);
+        }
+
+        if (memInfo.vmoHandle) {
+            zx_handle_close(memInfo.vmoHandle);
+        }
+
         if (memInfo.mappedPtr &&
             !memInfo.virtualHostVisibleBacking &&
             !memInfo.directMapped) {
@@ -287,7 +349,9 @@
                              VkDeviceSize allocationSize,
                              VkDeviceSize mappedSize,
                              uint8_t* ptr,
-                             uint32_t memoryTypeIndex) {
+                             uint32_t memoryTypeIndex,
+                             AHardwareBuffer* ahw = nullptr,
+                             zx_handle_t vmoHandle = ZX_HANDLE_INVALID) {
         AutoLock lock(mLock);
         auto& deviceInfo = info_VkDevice[device];
         auto& info = info_VkDeviceMemory[memory];
@@ -296,6 +360,8 @@
         info.mappedSize = mappedSize;
         info.mappedPtr = ptr;
         info.memoryTypeIndex = memoryTypeIndex;
+        info.ahw = ahw;
+        info.vmoHandle = vmoHandle;
     }
 
     bool isMemoryTypeHostVisible(VkDevice device, uint32_t typeIndex) const {
@@ -829,11 +895,11 @@
         auto& info = memoryIt->second;
 
         VkResult queryRes =
-            getMemoryAndroidHardwareBufferANDROID(info.ahbHandle);
+            getMemoryAndroidHardwareBufferANDROID(&info.ahw);
 
         if (queryRes != VK_SUCCESS) return queryRes;
 
-        *pBuffer = *(info.ahbHandle);
+        *pBuffer = info.ahw;
 
         return queryRes;
     }
@@ -850,52 +916,239 @@
 
         VkEncoder* enc = (VkEncoder*)context;
 
-        // Device local memory: pass through
-        if (!isHostVisibleMemoryTypeIndexForGuest(
+        VkMemoryAllocateInfo finalAllocInfo = *pAllocateInfo;
+        VkMemoryDedicatedAllocateInfo dedicatedAllocInfo;
+        VkImportColorBufferGOOGLE importCbInfo = {
+            VK_STRUCTURE_TYPE_IMPORT_COLOR_BUFFER_GOOGLE, 0,
+        };
+        VkImportPhysicalAddressGOOGLE importPhysAddrInfo = {
+            VK_STRUCTURE_TYPE_IMPORT_PHYSICAL_ADDRESS_GOOGLE, 0,
+        };
+
+        vk_struct_common* structChain =
+        structChain = vk_init_struct_chain(
+            (vk_struct_common*)(&finalAllocInfo));
+        structChain->pNext = nullptr;
+
+        VkExportMemoryAllocateInfo* exportAllocateInfoPtr =
+            (VkExportMemoryAllocateInfo*)vk_find_struct((vk_struct_common*)pAllocateInfo,
+                VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO);
+
+        VkImportAndroidHardwareBufferInfoANDROID* importAhbInfoPtr =
+            (VkImportAndroidHardwareBufferInfoANDROID*)vk_find_struct((vk_struct_common*)pAllocateInfo,
+                VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID);
+
+        // TODO: Fuchsia image works in a similar way but over vmo id (phys addr)?
+        VkImportPhysicalAddressGOOGLE* importPhysAddrInfoPtr = nullptr;
+
+        VkMemoryDedicatedAllocateInfo* dedicatedAllocInfoPtr =
+            (VkMemoryDedicatedAllocateInfo*)vk_find_struct((vk_struct_common*)pAllocateInfo,
+                VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO);
+
+        bool shouldPassThroughDedicatedAllocInfo =
+            !isHostVisibleMemoryTypeIndexForGuest(
+                &mHostVisibleMemoryVirtInfo,
+                pAllocateInfo->memoryTypeIndex);
+
+        if (!exportAllocateInfoPtr &&
+            importAhbInfoPtr && // TODO: Fuchsia image
+            dedicatedAllocInfoPtr &&
+            isHostVisibleMemoryTypeIndexForGuest(
                 &mHostVisibleMemoryVirtInfo,
                 pAllocateInfo->memoryTypeIndex)) {
+            ALOGE("FATAL: It is not yet supported to import-allocate "
+                  "external memory that is both host visible and dedicated.");
+            abort();
+        }
+
+        if (shouldPassThroughDedicatedAllocInfo &&
+            dedicatedAllocInfoPtr) {
+            dedicatedAllocInfo = *dedicatedAllocInfoPtr;
+            structChain->pNext =
+                (vk_struct_common*)(&dedicatedAllocInfo);
+            structChain =
+                (vk_struct_common*)(&dedicatedAllocInfo);
+            structChain->pNext = nullptr;
+        }
+
+        // State needed for import/export.
+        bool exportAhb = false;
+        bool exportPhysAddr = false;
+        bool importAhb = false;
+        bool importPhysAddr = false;
+        (void)exportPhysAddr;
+        (void)importPhysAddr;
+
+        // Even if we export allocate, the underlying operation
+        // for the host is always going to be an import operation.
+        // This is also how Intel's implementation works,
+        // and is generally simpler;
+        // even in an export allocation,
+        // we perform AHardwareBuffer allocation
+        // on the guest side, at this layer,
+        // and then we attach a new VkDeviceMemory
+        // to the AHardwareBuffer on the host via an "import" operation.
+        AHardwareBuffer* ahw = nullptr;
+        zx_handle_t vmo_handle = ZX_HANDLE_INVALID;
+
+        if (exportAllocateInfoPtr) {
+            exportAhb =
+                exportAllocateInfoPtr->handleTypes &
+                VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
+        } else if (importAhbInfoPtr) {
+            importAhb = true;
+        }
+
+        if (importPhysAddrInfoPtr) {
+            importPhysAddrInfo = *importPhysAddrInfoPtr;
+            importPhysAddr = true;
+        }
+
+        if (exportAhb) {
+            bool hasDedicatedImage = dedicatedAllocInfoPtr &&
+                (dedicatedAllocInfoPtr->image != VK_NULL_HANDLE);
+            bool hasDedicatedBuffer = dedicatedAllocInfoPtr &&
+                (dedicatedAllocInfoPtr->buffer != VK_NULL_HANDLE);
+            VkExtent3D imageExtent = { 0, 0, 0 };
+            uint32_t imageLayers = 0;
+            VkFormat imageFormat = VK_FORMAT_UNDEFINED;
+            VkImageUsageFlags imageUsage = 0;
+            VkImageCreateFlags imageCreateFlags = 0;
+            VkDeviceSize bufferSize = 0;
+            VkDeviceSize allocationInfoAllocSize =
+                finalAllocInfo.allocationSize;
+
+            if (hasDedicatedImage) {
+                AutoLock lock(mLock);
+
+                auto it = info_VkImage.find(
+                    dedicatedAllocInfoPtr->image);
+                if (it == info_VkImage.end()) return VK_ERROR_INITIALIZATION_FAILED;
+                const auto& info = it->second;
+                const auto& imgCi = info.createInfo;
+
+                imageExtent = imgCi.extent;
+                imageLayers = imgCi.arrayLayers;
+                imageFormat = imgCi.format;
+                imageUsage = imgCi.usage;
+                imageCreateFlags = imgCi.flags;
+            }
+
+            if (hasDedicatedBuffer) {
+                AutoLock lock(mLock);
+
+                auto it = info_VkBuffer.find(
+                    dedicatedAllocInfoPtr->buffer);
+                if (it == info_VkBuffer.end()) return VK_ERROR_INITIALIZATION_FAILED;
+                const auto& info = it->second;
+                const auto& bufCi = info.createInfo;
+
+                bufferSize = bufCi.size;
+            }
+
+            VkResult ahbCreateRes =
+                createAndroidHardwareBuffer(
+                    hasDedicatedImage,
+                    hasDedicatedBuffer,
+                    imageExtent,
+                    imageLayers,
+                    imageFormat,
+                    imageUsage,
+                    imageCreateFlags,
+                    bufferSize,
+                    allocationInfoAllocSize,
+                    &ahw);
+
+            if (ahbCreateRes != VK_SUCCESS) {
+                return ahbCreateRes;
+            }
+        }
+
+        if (importAhb) {
+            ahw = importAhbInfoPtr->buffer;
+            // We still need to acquire the AHardwareBuffer.
+            importAndroidHardwareBuffer(
+                importAhbInfoPtr, nullptr);
+        }
+
+        if (ahw) {
+            const native_handle_t *handle =
+                AHardwareBuffer_getNativeHandle(ahw);
+            const cb_handle_t* cb_handle =
+                reinterpret_cast<const cb_handle_t*>(handle);
+            importCbInfo.colorBuffer = cb_handle->hostHandle;
+            structChain =
+                vk_append_struct(structChain, (vk_struct_common*)(&importCbInfo));
+        }
+
+        // TODO if (exportPhysAddr) { }
+
+        if (!isHostVisibleMemoryTypeIndexForGuest(
+                &mHostVisibleMemoryVirtInfo,
+                finalAllocInfo.memoryTypeIndex)) {
 
             input_result =
                 enc->vkAllocateMemory(
-                    device, pAllocateInfo, pAllocator, pMemory);
+                    device, &finalAllocInfo, pAllocator, pMemory);
 
             if (input_result != VK_SUCCESS) return input_result;
 
-            VkDeviceSize allocationSize = pAllocateInfo->allocationSize;
+            VkDeviceSize allocationSize = finalAllocInfo.allocationSize;
             setDeviceMemoryInfo(
                 device, *pMemory,
-                pAllocateInfo->allocationSize,
+                finalAllocInfo.allocationSize,
                 0, nullptr,
-                pAllocateInfo->memoryTypeIndex);
+                finalAllocInfo.memoryTypeIndex,
+                ahw,
+                vmo_handle);
 
             return VK_SUCCESS;
         }
 
-        // Host visible memory with no direct mapping support
+        // Device-local memory dealing is over. What follows:
+        // host-visible memory.
+
+        if (ahw) {
+            ALOGE("%s: Host visible export/import allocation "
+                  "of Android hardware buffers is not supported.",
+                  __func__);
+            abort();
+        }
+
+        // Host visible memory, non external
         bool directMappingSupported = usingDirectMapping();
         if (!directMappingSupported) {
             input_result =
                 enc->vkAllocateMemory(
-                    device, pAllocateInfo, pAllocator, pMemory);
+                    device, &finalAllocInfo, pAllocator, pMemory);
 
             if (input_result != VK_SUCCESS) return input_result;
 
             VkDeviceSize mappedSize =
                 getNonCoherentExtendedSize(device,
-                    pAllocateInfo->allocationSize);
+                    finalAllocInfo.allocationSize);
             uint8_t* mappedPtr = (uint8_t*)aligned_buf_alloc(4096, mappedSize);
             D("host visible alloc (non-direct): "
               "size 0x%llx host ptr %p mapped size 0x%llx",
-              (unsigned long long)pAllocateInfo->allocationSize, mappedPtr,
+              (unsigned long long)finalAllocInfo.allocationSize, mappedPtr,
               (unsigned long long)mappedSize);
             setDeviceMemoryInfo(
                 device, *pMemory,
-                pAllocateInfo->allocationSize,
+                finalAllocInfo.allocationSize,
                 mappedSize, mappedPtr,
-                pAllocateInfo->memoryTypeIndex);
+                finalAllocInfo.memoryTypeIndex);
             return VK_SUCCESS;
         }
 
+        // Host visible memory with direct mapping via
+        // VkImportPhysicalAddressGOOGLE
+        if (importPhysAddr) {
+            // vkAllocateMemory(device, &finalAllocInfo, pAllocator, pMemory);
+            //    host maps the host pointer to the guest physical address
+            // TODO: the host side page offset of the
+            // host pointer needs to be returned somehow.
+        }
+
         // Host visible memory with direct mapping
         AutoLock lock(mLock);
 
@@ -904,10 +1157,10 @@
         auto& deviceInfo = it->second;
 
         HostMemAlloc* hostMemAlloc =
-            &deviceInfo.hostMemAllocs[pAllocateInfo->memoryTypeIndex];
+            &deviceInfo.hostMemAllocs[finalAllocInfo.memoryTypeIndex];
 
         if (!hostMemAlloc->initialized) {
-            VkMemoryAllocateInfo allocInfoForHost = *pAllocateInfo;
+            VkMemoryAllocateInfo allocInfoForHost = finalAllocInfo;
             allocInfoForHost.allocationSize = VIRTUAL_HOST_VISIBLE_HEAP_SIZE;
             // TODO: Support dedicated allocation
             allocInfoForHost.pNext = nullptr;
@@ -935,7 +1188,7 @@
                 deviceInfo.props.limits.nonCoherentAtomSize;
             hostMemInfo.mappedSize = hostMemInfo.allocationSize;
             hostMemInfo.memoryTypeIndex =
-                pAllocateInfo->memoryTypeIndex;
+                finalAllocInfo.memoryTypeIndex;
             hostMemAlloc->nonCoherentAtomSize = nonCoherentAtomSize;
 
             uint64_t directMappedAddr = 0;
@@ -959,7 +1212,7 @@
                 finishHostMemAllocInit(
                     enc,
                     device,
-                    pAllocateInfo->memoryTypeIndex,
+                    finalAllocInfo.memoryTypeIndex,
                     nonCoherentAtomSize,
                     hostMemInfo.allocationSize,
                     hostMemInfo.mappedSize,
@@ -975,13 +1228,13 @@
 
         subAllocHostMemory(
             hostMemAlloc,
-            pAllocateInfo,
+            &finalAllocInfo,
             &virtualMemInfo.subAlloc);
 
         virtualMemInfo.allocationSize = virtualMemInfo.subAlloc.subAllocSize;
         virtualMemInfo.mappedSize = virtualMemInfo.subAlloc.subMappedSize;
         virtualMemInfo.mappedPtr = virtualMemInfo.subAlloc.mappedPtr;
-        virtualMemInfo.memoryTypeIndex = pAllocateInfo->memoryTypeIndex;
+        virtualMemInfo.memoryTypeIndex = finalAllocInfo.memoryTypeIndex;
         virtualMemInfo.directMapped = true;
 
         D("host visible alloc (direct, suballoc): "