(8/8) vulkan_enc: Support sysmem VkBuffer allocation in Fuchsia.

Now goldfish Vulkan clients can allocate VkBuffer using sysmem
BufferCollection in Fuchsia, for example:

```
vk::StructureChain<vk::BufferCreateInfo,
    vk::BufferCollectionBufferCreateInfoFUCHSIA> chain = {
  vk::BufferCreateInfo({}, size, bufferUsage),
  vk::BufferCollectionBufferCreateInfoFUCHSIA(vk_collection, 0),
};
auto vkBuffer = device.createBuffer(chain.get<vk::BufferCreateInfo>());
```

Then clients can import BufferCollection info to
VkDeviceMemory by calling vkAllocateMemory().

These buffer will have host renderControl buffer backing,
and can be exported to other processes.

Change-Id: Iaa7d326e75c1c97ef0320612d4f9da46cf0182d7
diff --git a/system/vulkan_enc/ResourceTracker.cpp b/system/vulkan_enc/ResourceTracker.cpp
index 91be62b..c364b32 100644
--- a/system/vulkan_enc/ResourceTracker.cpp
+++ b/system/vulkan_enc/ResourceTracker.cpp
@@ -15,6 +15,7 @@
 
 #include "ResourceTracker.h"
 
+#include "android/base/Optional.h"
 #include "android/base/threads/AndroidWorkPool.h"
 
 #include "goldfish_vk_private_defs.h"
@@ -160,6 +161,7 @@
 
 using android::aligned_buf_alloc;
 using android::aligned_buf_free;
+using android::base::Optional;
 using android::base::guest::AutoLock;
 using android::base::guest::Lock;
 using android::base::guest::WorkPool;
@@ -299,6 +301,9 @@
         VkDeviceSize currentBackingSize = 0;
         bool baseRequirementsKnown = false;
         VkMemoryRequirements baseRequirements;
+#ifdef VK_USE_PLATFORM_FUCHSIA
+        bool isSysmemBackedMemory = false;
+#endif
     };
 
     struct VkSemaphore_Info {
@@ -1694,56 +1699,66 @@
         buffer_constraints.heap_permitted_count = 1;
         buffer_constraints.heap_permitted[0] =
             fuchsia::sysmem::HeapType::GOLDFISH_DEVICE_LOCAL;
-        std::vector<VkFormat> formats{pImageInfo->format};
-        if (pImageInfo->format == VK_FORMAT_UNDEFINED) {
-            // This is a hack to allow the client to say it supports every vulkan format the driver
-            // does. TODO(fxb/13247): Modify this function to take a list of vulkan formats to use.
-            formats = std::vector<VkFormat>{
-                VK_FORMAT_B8G8R8A8_UNORM,
-                VK_FORMAT_R8G8B8A8_UNORM,
-            };
-        }
-        constraints.image_format_constraints_count = formats.size();
-        uint32_t format_index = 0;
-        for (VkFormat format : formats) {
-            fuchsia::sysmem::ImageFormatConstraints& image_constraints =
-                constraints.image_format_constraints[format_index++];
-            switch (format) {
-            case VK_FORMAT_B8G8R8A8_SINT:
-            case VK_FORMAT_B8G8R8A8_UNORM:
-            case VK_FORMAT_B8G8R8A8_SRGB:
-            case VK_FORMAT_B8G8R8A8_SNORM:
-            case VK_FORMAT_B8G8R8A8_SSCALED:
-            case VK_FORMAT_B8G8R8A8_USCALED:
-                image_constraints.pixel_format.type = fuchsia::sysmem::PixelFormatType::BGRA32;
-                break;
-            case VK_FORMAT_R8G8B8A8_SINT:
-            case VK_FORMAT_R8G8B8A8_UNORM:
-            case VK_FORMAT_R8G8B8A8_SRGB:
-            case VK_FORMAT_R8G8B8A8_SNORM:
-            case VK_FORMAT_R8G8B8A8_SSCALED:
-            case VK_FORMAT_R8G8B8A8_USCALED:
-                image_constraints.pixel_format.type = fuchsia::sysmem::PixelFormatType::R8G8B8A8;
-                break;
-            default:
-                return VK_ERROR_FORMAT_NOT_SUPPORTED;
+
+        // Set image format constraints for VkImage allocation.
+        if (pImageInfo) {
+            std::vector<VkFormat> formats{pImageInfo->format};
+            if (pImageInfo->format == VK_FORMAT_UNDEFINED) {
+                // This is a hack to allow the client to say it supports every
+                // vulkan format the driver does. TODO(fxb/13247): Modify this
+                // function to take a list of vulkan formats to use.
+                formats = std::vector<VkFormat>{
+                        VK_FORMAT_B8G8R8A8_UNORM,
+                        VK_FORMAT_R8G8B8A8_UNORM,
+                };
             }
-            image_constraints.color_spaces_count = 1;
-            image_constraints.color_space[0].type = fuchsia::sysmem::ColorSpaceType::SRGB;
-            image_constraints.min_coded_width = pImageInfo->extent.width;
-            image_constraints.max_coded_width = 0xfffffff;
-            image_constraints.min_coded_height = pImageInfo->extent.height;
-            image_constraints.max_coded_height = 0xffffffff;
-            image_constraints.min_bytes_per_row = pImageInfo->extent.width * 4;
-            image_constraints.max_bytes_per_row = 0xffffffff;
-            image_constraints.max_coded_width_times_coded_height = 0xffffffff;
-            image_constraints.layers = 1;
-            image_constraints.coded_width_divisor = 1;
-            image_constraints.coded_height_divisor = 1;
-            image_constraints.bytes_per_row_divisor = 1;
-            image_constraints.start_offset_divisor = 1;
-            image_constraints.display_width_divisor = 1;
-            image_constraints.display_height_divisor = 1;
+            constraints.image_format_constraints_count = formats.size();
+            uint32_t format_index = 0;
+            for (VkFormat format : formats) {
+                fuchsia::sysmem::ImageFormatConstraints& image_constraints =
+                        constraints.image_format_constraints[format_index++];
+                switch (format) {
+                    case VK_FORMAT_B8G8R8A8_SINT:
+                    case VK_FORMAT_B8G8R8A8_UNORM:
+                    case VK_FORMAT_B8G8R8A8_SRGB:
+                    case VK_FORMAT_B8G8R8A8_SNORM:
+                    case VK_FORMAT_B8G8R8A8_SSCALED:
+                    case VK_FORMAT_B8G8R8A8_USCALED:
+                        image_constraints.pixel_format.type =
+                                fuchsia::sysmem::PixelFormatType::BGRA32;
+                        break;
+                    case VK_FORMAT_R8G8B8A8_SINT:
+                    case VK_FORMAT_R8G8B8A8_UNORM:
+                    case VK_FORMAT_R8G8B8A8_SRGB:
+                    case VK_FORMAT_R8G8B8A8_SNORM:
+                    case VK_FORMAT_R8G8B8A8_SSCALED:
+                    case VK_FORMAT_R8G8B8A8_USCALED:
+                        image_constraints.pixel_format.type =
+                                fuchsia::sysmem::PixelFormatType::R8G8B8A8;
+                        break;
+                    default:
+                        return VK_ERROR_FORMAT_NOT_SUPPORTED;
+                }
+                image_constraints.color_spaces_count = 1;
+                image_constraints.color_space[0].type =
+                        fuchsia::sysmem::ColorSpaceType::SRGB;
+                image_constraints.min_coded_width = pImageInfo->extent.width;
+                image_constraints.max_coded_width = 0xfffffff;
+                image_constraints.min_coded_height = pImageInfo->extent.height;
+                image_constraints.max_coded_height = 0xffffffff;
+                image_constraints.min_bytes_per_row =
+                        pImageInfo->extent.width * 4;
+                image_constraints.max_bytes_per_row = 0xffffffff;
+                image_constraints.max_coded_width_times_coded_height =
+                        0xffffffff;
+                image_constraints.layers = 1;
+                image_constraints.coded_width_divisor = 1;
+                image_constraints.coded_height_divisor = 1;
+                image_constraints.bytes_per_row_divisor = 1;
+                image_constraints.start_offset_divisor = 1;
+                image_constraints.display_width_divisor = 1;
+                image_constraints.display_height_divisor = 1;
+            }
         }
 
         (*collection)->SetConstraints(true, constraints);
@@ -1756,9 +1771,11 @@
         const VkImageCreateInfo* pImageInfo) {
         auto sysmem_collection =
             reinterpret_cast<fuchsia::sysmem::BufferCollectionSyncPtr*>(collection);
-        return setBufferCollectionConstraints(
-            sysmem_collection, pImageInfo,
-            pImageInfo->extent.width * pImageInfo->extent.height * 4);
+        size_t minSizeBytes = pImageInfo ? pImageInfo->extent.width *
+                                                   pImageInfo->extent.height * 4
+                                         : 0u;
+        return setBufferCollectionConstraints(sysmem_collection, pImageInfo,
+                                              minSizeBytes);
     }
 
     VkResult on_vkGetBufferCollectionPropertiesFUCHSIA(
@@ -1991,6 +2008,10 @@
         VkImportColorBufferGOOGLE importCbInfo = {
             VK_STRUCTURE_TYPE_IMPORT_COLOR_BUFFER_GOOGLE, 0,
         };
+        VkImportBufferGOOGLE importBufferInfo = {
+                VK_STRUCTURE_TYPE_IMPORT_BUFFER_GOOGLE,
+                0,
+        };
         // VkImportPhysicalAddressGOOGLE importPhysAddrInfo = {
         //     VK_STRUCTURE_TYPE_IMPORT_PHYSICAL_ADDRESS_GOOGLE, 0,
         // };
@@ -2180,6 +2201,7 @@
                 (dedicatedAllocInfoPtr->image != VK_NULL_HANDLE);
             VkImageCreateInfo imageCreateInfo = {};
 
+            // TODO(liyl): Handle dedicated buffer allocation as well.
             if (hasDedicatedImage) {
                 AutoLock lock(mLock);
 
@@ -2288,12 +2310,25 @@
                 abort();
             }
             zx_status_t status2 = ZX_OK;
-            status = mControlDevice->GetColorBuffer(
-                std::move(vmo_copy), &status2, &importCbInfo.colorBuffer);
+
+            fuchsia::hardware::goldfish::BufferHandleType handle_type;
+            uint32_t buffer_handle;
+
+            status = mControlDevice->GetBufferHandle(std::move(vmo_copy),
+                                                     &status2, &buffer_handle,
+                                                     &handle_type);
             if (status != ZX_OK || status2 != ZX_OK) {
-                ALOGE("GetColorBuffer failed: %d:%d", status, status2);
+                ALOGE("GetBufferHandle failed: %d:%d", status, status2);
             }
-            vk_append_struct(&structChainIter, &importCbInfo);
+
+            if (handle_type ==
+                fuchsia::hardware::goldfish::BufferHandleType::BUFFER) {
+                importBufferInfo.buffer = buffer_handle;
+                vk_append_struct(&structChainIter, &importBufferInfo);
+            } else {
+                importCbInfo.colorBuffer = buffer_handle;
+                vk_append_struct(&structChainIter, &importCbInfo);
+            }
         }
 #endif
 
@@ -3503,6 +3538,47 @@
         VkBuffer *pBuffer) {
         VkEncoder* enc = (VkEncoder*)context;
 
+#ifdef VK_USE_PLATFORM_FUCHSIA
+        Optional<zx::vmo> vmo;
+        bool isSysmemBackedMemory = false;
+
+        const auto* extBufferCollectionPtr =
+                vk_find_struct<VkBufferCollectionBufferCreateInfoFUCHSIA>(
+                        pCreateInfo);
+
+        if (extBufferCollectionPtr) {
+            auto collection =
+                    reinterpret_cast<fuchsia::sysmem::BufferCollectionSyncPtr*>(
+                            extBufferCollectionPtr->collection);
+            uint32_t index = extBufferCollectionPtr->index;
+
+            fuchsia::sysmem::BufferCollectionInfo_2 info;
+            zx_status_t status2;
+            zx_status_t status =
+                    (*collection)->WaitForBuffersAllocated(&status2, &info);
+
+            if (status == ZX_OK && status2 == ZX_OK) {
+                if (index < info.buffer_count) {
+                    vmo = android::base::makeOptional(
+                            std::move(info.buffers[index].vmo));
+                }
+            } else {
+                ALOGE("WaitForBuffersAllocated failed: %d %d", status, status2);
+            }
+
+            if (vmo && vmo->is_valid()) {
+                zx_status_t status2 = ZX_OK;
+                status = mControlDevice->CreateBuffer(
+                        std::move(*vmo), pCreateInfo->size, &status2);
+                if (status != ZX_OK ||
+                    (status2 != ZX_OK && status2 != ZX_ERR_ALREADY_EXISTS)) {
+                    ALOGE("CreateBuffer failed: %d:%d", status, status2);
+                }
+                isSysmemBackedMemory = true;
+            }
+        }
+#endif  // VK_USE_PLATFORM_FUCHSIA
+
         VkResult res;
         VkMemoryRequirements memReqs;
 
@@ -3536,6 +3612,12 @@
             info.externalCreateInfo = *extBufCi;
         }
 
+#ifdef VK_USE_PLATFORM_FUCHSIA
+        if (isSysmemBackedMemory) {
+            info.isSysmemBackedMemory = true;
+        }
+#endif
+
         if (info.baseRequirementsKnown) {
             transformBufferMemoryRequirementsForGuestLocked(*pBuffer, &memReqs);
             info.baseRequirements = memReqs;
@@ -3967,7 +4049,7 @@
         }
 
         for (auto handle : toWait) {
-            ALOGV("%s: waiting on work group item: %llu\n", __func__, 
+            ALOGV("%s: waiting on work group item: %llu\n", __func__,
                   (unsigned long long)handle);
             mWorkPool.waitAll(handle);
         }