fuchsia: Support vkSetBufferCollectionBufferConstraintsFUCHSIA.

Similar to |vkSetBufferCollectionConstraintsFUCHSIA|,
this method sets sysmem BufferCollection constraints for Vulkan
buffers, which will be required for clients if they allocates
buffers via sysmem.

Change-Id: I5f6df09b89cd3b7e7e97679efe84a1bc3ea4f0e1
diff --git a/system/vulkan/goldfish_vulkan.cpp b/system/vulkan/goldfish_vulkan.cpp
index 44071ec..b62ce7b 100644
--- a/system/vulkan/goldfish_vulkan.cpp
+++ b/system/vulkan/goldfish_vulkan.cpp
@@ -221,6 +221,14 @@
     return VK_SUCCESS;
 }
 
+VkResult SetBufferCollectionBufferConstraintsFUCHSIA(
+    VkDevice /*device*/,
+    VkBufferCollectionFUCHSIA /*collection*/,
+    const VkBufferConstraintsInfoFUCHSIA* /*pBufferConstraintsInfo*/) {
+    AEMU_SCOPED_TRACE("vkstubhal::SetBufferCollectionBufferConstraintsFUCHSIA");
+    return VK_SUCCESS;
+}
+
 VkResult
 GetBufferCollectionPropertiesFUCHSIA(VkDevice /*device*/,
                                      VkBufferCollectionFUCHSIA /*collection*/,
@@ -279,6 +287,8 @@
         return reinterpret_cast<PFN_vkVoidFunction>(DestroyBufferCollectionFUCHSIA);
     if (strcmp(name, "vkSetBufferCollectionConstraintsFUCHSIA") == 0)
         return reinterpret_cast<PFN_vkVoidFunction>(SetBufferCollectionConstraintsFUCHSIA);
+    if (strcmp(name, "vkSetBufferCollectionBufferConstraintsFUCHSIA") == 0)
+        return reinterpret_cast<PFN_vkVoidFunction>(SetBufferCollectionBufferConstraintsFUCHSIA);
     if (strcmp(name, "vkGetBufferCollectionPropertiesFUCHSIA") == 0)
         return reinterpret_cast<PFN_vkVoidFunction>(GetBufferCollectionPropertiesFUCHSIA);
 #endif
@@ -554,6 +564,27 @@
 }
 
 VKAPI_ATTR
+VkResult SetBufferCollectionBufferConstraintsFUCHSIA(
+    VkDevice device,
+    VkBufferCollectionFUCHSIA collection,
+    const VkBufferConstraintsInfoFUCHSIA* pBufferConstraintsInfo) {
+    AEMU_SCOPED_TRACE("goldfish_vulkan::SetBufferCollectionBufferConstraintsFUCHSIA");
+
+    VK_HOST_CONNECTION(VK_ERROR_DEVICE_LOST)
+
+    if (!hostSupportsVulkan) {
+        return vkstubhal::SetBufferCollectionBufferConstraintsFUCHSIA(device, collection,
+                                                                      pBufferConstraintsInfo);
+    }
+
+    VkResult res =
+        goldfish_vk::ResourceTracker::get()->on_vkSetBufferCollectionBufferConstraintsFUCHSIA(
+            vkEnc, VK_SUCCESS, device, collection, pBufferConstraintsInfo);
+
+    return res;
+}
+
+VKAPI_ATTR
 VkResult GetBufferCollectionPropertiesFUCHSIA(
     VkDevice device,
     VkBufferCollectionFUCHSIA collection,
@@ -605,6 +636,9 @@
     if (!strcmp(name, "vkSetBufferCollectionConstraintsFUCHSIA")) {
         return (PFN_vkVoidFunction)SetBufferCollectionConstraintsFUCHSIA;
     }
+    if (!strcmp(name, "vkSetBufferCollectionBufferConstraintsFUCHSIA")) {
+        return (PFN_vkVoidFunction)SetBufferCollectionBufferConstraintsFUCHSIA;
+    }
     if (!strcmp(name, "vkGetBufferCollectionPropertiesFUCHSIA")) {
         return (PFN_vkVoidFunction)GetBufferCollectionPropertiesFUCHSIA;
     }
diff --git a/system/vulkan_enc/ResourceTracker.cpp b/system/vulkan_enc/ResourceTracker.cpp
index 44da142..d3f33f2 100644
--- a/system/vulkan_enc/ResourceTracker.cpp
+++ b/system/vulkan_enc/ResourceTracker.cpp
@@ -1680,18 +1680,15 @@
         delete sysmem_collection;
     }
 
-    VkResult setBufferCollectionConstraints(fuchsia::sysmem::BufferCollectionSyncPtr* collection,
-                                            const VkImageCreateInfo* pImageInfo,
-                                            size_t min_size_bytes) {
+    inline fuchsia::sysmem::BufferCollectionConstraints
+    defaultBufferCollectionConstraints(size_t min_size_bytes,
+                                       size_t buffer_count) {
         fuchsia::sysmem::BufferCollectionConstraints constraints = {};
-        constraints.usage.vulkan = fuchsia::sysmem::vulkanUsageColorAttachment |
-                                   fuchsia::sysmem::vulkanUsageTransferSrc |
-                                   fuchsia::sysmem::vulkanUsageTransferDst |
-                                   fuchsia::sysmem::vulkanUsageSampled;
-        constraints.min_buffer_count = 1;
+        constraints.min_buffer_count = buffer_count;
         constraints.has_buffer_memory_constraints = true;
         fuchsia::sysmem::BufferMemoryConstraints& buffer_constraints =
             constraints.buffer_memory_constraints;
+
         buffer_constraints.min_size_bytes = min_size_bytes;
         buffer_constraints.max_size_bytes = 0xffffffff;
         buffer_constraints.physically_contiguous_required = false;
@@ -1703,6 +1700,72 @@
         buffer_constraints.heap_permitted[0] =
             fuchsia::sysmem::HeapType::GOLDFISH_DEVICE_LOCAL;
 
+        return constraints;
+    }
+
+    uint32_t getBufferCollectionConstraintsVulkanImageUsage(
+        const VkImageCreateInfo* pImageInfo) {
+        uint32_t usage = 0u;
+        VkImageUsageFlags imageUsage = pImageInfo->usage;
+
+#define SetUsageBit(USAGE)                                    \
+    if (imageUsage & VK_IMAGE_USAGE_##USAGE##_BIT) {          \
+        usage |= fuchsia::sysmem::VULKAN_IMAGE_USAGE_##USAGE; \
+    }
+
+        SetUsageBit(COLOR_ATTACHMENT);
+        SetUsageBit(TRANSFER_SRC);
+        SetUsageBit(TRANSFER_DST);
+        SetUsageBit(SAMPLED);
+
+#undef SetUsageBit
+        return usage;
+    }
+
+    uint32_t getBufferCollectionConstraintsVulkanBufferUsage(
+        const VkBufferConstraintsInfoFUCHSIA* pBufferConstraintsInfo) {
+        uint32_t usage = 0u;
+        VkBufferUsageFlags bufferUsage =
+            pBufferConstraintsInfo->pBufferCreateInfo->usage;
+
+#define SetUsageBit(USAGE)                                     \
+    if (bufferUsage & VK_BUFFER_USAGE_##USAGE##_BIT) {         \
+        usage |= fuchsia::sysmem::VULKAN_BUFFER_USAGE_##USAGE; \
+    }
+
+        SetUsageBit(TRANSFER_SRC);
+        SetUsageBit(TRANSFER_DST);
+        SetUsageBit(UNIFORM_TEXEL_BUFFER);
+        SetUsageBit(STORAGE_TEXEL_BUFFER);
+        SetUsageBit(UNIFORM_BUFFER);
+        SetUsageBit(STORAGE_BUFFER);
+        SetUsageBit(INDEX_BUFFER);
+        SetUsageBit(VERTEX_BUFFER);
+        SetUsageBit(INDIRECT_BUFFER);
+
+#undef SetUsageBit
+        return usage;
+    }
+
+    VkResult setBufferCollectionConstraints(
+        fuchsia::sysmem::BufferCollectionSyncPtr* collection,
+        const VkImageCreateInfo* pImageInfo) {
+        if (pImageInfo == nullptr) {
+            ALOGE("setBufferCollectionConstraints: pImageInfo cannot be null.");
+            return VK_ERROR_OUT_OF_DEVICE_MEMORY;
+        }
+
+        // TODO(liyl): Currently the size only works for RGBA8 and BGRA8 images.
+        // We should set the size based on its actual format.
+        fuchsia::sysmem::BufferCollectionConstraints constraints =
+            defaultBufferCollectionConstraints(
+                /* min_size_bytes */ pImageInfo->extent.width *
+                    pImageInfo->extent.height * 4,
+                /* buffer_count */ 1u);
+
+        constraints.usage.vulkan =
+            getBufferCollectionConstraintsVulkanImageUsage(pImageInfo);
+
         // Set image format constraints for VkImage allocation.
         if (pImageInfo) {
             std::vector<VkFormat> formats{pImageInfo->format};
@@ -1768,17 +1831,49 @@
         return VK_SUCCESS;
     }
 
+    VkResult setBufferCollectionBufferConstraints(
+        fuchsia::sysmem::BufferCollectionSyncPtr* collection,
+        const VkBufferConstraintsInfoFUCHSIA* pBufferConstraintsInfo) {
+        if (pBufferConstraintsInfo == nullptr) {
+            ALOGE(
+                "setBufferCollectionBufferConstraints: "
+                "pBufferConstraintsInfo cannot be null.");
+            return VK_ERROR_OUT_OF_DEVICE_MEMORY;
+        }
+
+        fuchsia::sysmem::BufferCollectionConstraints constraints =
+            defaultBufferCollectionConstraints(
+                /* min_size_bytes */ pBufferConstraintsInfo->pBufferCreateInfo
+                    ->size,
+                /* buffer_count */ pBufferConstraintsInfo->minCount);
+        constraints.usage.vulkan =
+            getBufferCollectionConstraintsVulkanBufferUsage(
+                pBufferConstraintsInfo);
+
+        (*collection)->SetConstraints(true, constraints);
+        return VK_SUCCESS;
+    }
+
     VkResult on_vkSetBufferCollectionConstraintsFUCHSIA(
         void*, VkResult, VkDevice,
         VkBufferCollectionFUCHSIA collection,
         const VkImageCreateInfo* pImageInfo) {
         auto sysmem_collection =
             reinterpret_cast<fuchsia::sysmem::BufferCollectionSyncPtr*>(collection);
-        size_t minSizeBytes = pImageInfo ? pImageInfo->extent.width *
-                                                   pImageInfo->extent.height * 4
-                                         : 0u;
-        return setBufferCollectionConstraints(sysmem_collection, pImageInfo,
-                                              minSizeBytes);
+        return setBufferCollectionConstraints(sysmem_collection, pImageInfo);
+    }
+
+    VkResult on_vkSetBufferCollectionBufferConstraintsFUCHSIA(
+        void*,
+        VkResult,
+        VkDevice,
+        VkBufferCollectionFUCHSIA collection,
+        const VkBufferConstraintsInfoFUCHSIA* pBufferConstraintsInfo) {
+        auto sysmem_collection =
+            reinterpret_cast<fuchsia::sysmem::BufferCollectionSyncPtr*>(
+                collection);
+        return setBufferCollectionBufferConstraints(sysmem_collection,
+                                                    pBufferConstraintsInfo);
     }
 
     VkResult on_vkGetBufferCollectionPropertiesFUCHSIA(
@@ -2234,9 +2329,9 @@
                     ALOGE("BindSharedCollection failed: %d", status);
                     abort();
                 }
+
                 VkResult res = setBufferCollectionConstraints(&collection,
-                                                              &imageCreateInfo,
-                                                              finalAllocInfo.allocationSize);
+                                                              &imageCreateInfo);
                 if (res != VK_SUCCESS) {
                     ALOGE("setBufferCollectionConstraints failed: %d", res);
                     abort();
@@ -5088,6 +5183,15 @@
         context, input_result, device, collection, pImageInfo);
 }
 
+VkResult ResourceTracker::on_vkSetBufferCollectionBufferConstraintsFUCHSIA(
+        void* context, VkResult input_result,
+        VkDevice device,
+        VkBufferCollectionFUCHSIA collection,
+        const VkBufferConstraintsInfoFUCHSIA* pBufferDConstraintsInfo) {
+    return mImpl->on_vkSetBufferCollectionBufferConstraintsFUCHSIA(
+        context, input_result, device, collection, pBufferDConstraintsInfo);
+}
+
 VkResult ResourceTracker::on_vkGetBufferCollectionPropertiesFUCHSIA(
         void* context, VkResult input_result,
         VkDevice device,
diff --git a/system/vulkan_enc/ResourceTracker.h b/system/vulkan_enc/ResourceTracker.h
index 63cfc41..db33285 100644
--- a/system/vulkan_enc/ResourceTracker.h
+++ b/system/vulkan_enc/ResourceTracker.h
@@ -274,6 +274,12 @@
         VkDevice device,
         VkBufferCollectionFUCHSIA collection,
         const VkImageCreateInfo* pImageInfo);
+    VkResult on_vkSetBufferCollectionBufferConstraintsFUCHSIA(
+        void* context,
+        VkResult input_result,
+        VkDevice device,
+        VkBufferCollectionFUCHSIA collection,
+        const VkBufferConstraintsInfoFUCHSIA* pBufferConstraintsInfo);
     VkResult on_vkGetBufferCollectionPropertiesFUCHSIA(
         void* context, VkResult input_result,
         VkDevice device,
diff --git a/system/vulkan_enc/goldfish_vk_private_defs.h b/system/vulkan_enc/goldfish_vk_private_defs.h
index b95517d..e7b0622 100644
--- a/system/vulkan_enc/goldfish_vk_private_defs.h
+++ b/system/vulkan_enc/goldfish_vk_private_defs.h
@@ -504,6 +504,14 @@
 #define VK_FUCHSIA_EXTERNAL_MEMORY_SPEC_VERSION 1
 #define VK_FUCHSIA_EXTERNAL_MEMORY_EXTENSION_NAME "VK_FUCHSIA_external_memory"
 
+typedef struct VkBufferConstraintsInfoFUCHSIA {
+    VkStructureType sType;
+    const void* pNext;
+    const VkBufferCreateInfo* pBufferCreateInfo;
+    VkFormatFeatureFlags requiredFormatFeatures;
+    uint32_t minCount;
+} VkBufferConstraintsInfoFUCHSIA;
+
 typedef struct VkImportMemoryZirconHandleInfoFUCHSIA {
     VkStructureType                       sType;
     const void*                           pNext;
@@ -524,6 +532,8 @@
     VkExternalMemoryHandleTypeFlagBits    handleType;
 } VkMemoryGetZirconHandleInfoFUCHSIA;
 
+#define VK_STRUCTURE_TYPE_BUFFER_COLLECTION_BUFFER_CREATE_INFO_FUCHSIA \
+    ((VkStructureType)1001004008)
 #define VK_STRUCTURE_TYPE_TEMP_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA \
     ((VkStructureType)1001005000)
 #define VK_STRUCTURE_TYPE_TEMP_MEMORY_ZIRCON_HANDLE_PROPERTIES_FUCHSIA \