[vulkan] Minimal implementation of VK_FUCHSIA_buffer_collection

Change-Id: Ic6886369e5a1fd62abc071df1290dcab8cc375b4
diff --git a/system/vulkan_enc/ResourceTracker.cpp b/system/vulkan_enc/ResourceTracker.cpp
index 4cc20ee..275119f 100644
--- a/system/vulkan_enc/ResourceTracker.cpp
+++ b/system/vulkan_enc/ResourceTracker.cpp
@@ -48,7 +48,13 @@
 
 #include <cutils/native_handle.h>
 #include <fuchsia/hardware/goldfish/c/fidl.h>
+#include <fuchsia/sysmem/cpp/fidl.h>
+#include <lib/fdio/directory.h>
+#include <lib/fdio/fd.h>
+#include <lib/fdio/fdio.h>
+#include <lib/fdio/io.h>
 #include <lib/fzl/fdio.h>
+#include <lib/zx/channel.h>
 #include <zircon/process.h>
 #include <zircon/syscalls.h>
 #include <zircon/syscalls/object.h>
@@ -523,6 +529,15 @@
             mGoldfishAddressSpaceBlockProvider.reset(
                 new GoldfishAddressSpaceBlockProvider);
         }
+
+#ifdef VK_USE_PLATFORM_FUCHSIA
+        zx_status_t status = fdio_service_connect(
+            "/svc/fuchsia.sysmem.Allocator",
+            mSysmemAllocator.NewRequest().TakeChannel().release());
+        if (status != ZX_OK) {
+            ALOGE("failed to connect to sysmem service, status %d", status);
+        }
+#endif
     }
 
     bool hostSupportsVulkan() const {
@@ -830,6 +845,7 @@
             { "VK_KHR_external_memory_fuchsia", 1 },
             { "VK_KHR_external_semaphore", 1 },
             { "VK_KHR_external_semaphore_fuchsia", 1 },
+            { "VK_FUCHSIA_buffer_collection", 1 },
 #endif
         };
 
@@ -1103,7 +1119,7 @@
         auto& info = memoryIt->second;
 
         if (info.vmoHandle == ZX_HANDLE_INVALID) {
-            ALOGE("%s: memory cannot be exported: %d", __func__);
+            ALOGE("%s: memory cannot be exported", __func__);
             return VK_ERROR_INITIALIZATION_FAILED;
         }
 
@@ -1187,6 +1203,87 @@
         zx_handle_duplicate(info.eventHandle, ZX_RIGHT_SAME_RIGHTS, pHandle);
         return VK_SUCCESS;
     }
+
+    VkResult on_vkCreateBufferCollectionFUCHSIA(
+        void*, VkResult, VkDevice,
+        const VkBufferCollectionCreateInfoFUCHSIA* pInfo,
+        const VkAllocationCallbacks*,
+        VkBufferCollectionFUCHSIA* pCollection) {
+        fuchsia::sysmem::BufferCollectionTokenSyncPtr token;
+        if (pInfo->collectionToken) {
+            token.Bind(zx::channel(pInfo->collectionToken));
+        } else {
+            zx_status_t status = mSysmemAllocator->AllocateSharedCollection(token.NewRequest());
+            if (status != ZX_OK) {
+                ALOGE("AllocateSharedCollection failed: %d", status);
+                return VK_ERROR_INITIALIZATION_FAILED;
+            }
+        }
+        auto sysmem_collection = new fuchsia::sysmem::BufferCollectionSyncPtr;
+        zx_status_t status = mSysmemAllocator->BindSharedCollection(
+            token, sysmem_collection->NewRequest());
+        if (status != ZX_OK) {
+            ALOGE("BindSharedCollection failed: %d", status);
+            return VK_ERROR_INITIALIZATION_FAILED;
+        }
+        *pCollection = reinterpret_cast<VkBufferCollectionFUCHSIA>(sysmem_collection);
+        return VK_SUCCESS;
+    }
+
+    void on_vkDestroyBufferCollectionFUCHSIA(
+        void*, VkResult, VkDevice,
+        VkBufferCollectionFUCHSIA collection,
+        const VkAllocationCallbacks*) {
+        auto sysmem_collection = reinterpret_cast<fuchsia::sysmem::BufferCollectionSyncPtr*>(collection);
+        if (sysmem_collection->is_bound()) {
+            (*sysmem_collection)->Close();
+        }
+        delete sysmem_collection;
+    }
+
+    VkResult on_vkSetBufferCollectionConstraintsFUCHSIA(
+        void*, VkResult, VkDevice,
+        VkBufferCollectionFUCHSIA collection,
+        const VkImageCreateInfo* pImageInfo) {
+        fuchsia::sysmem::BufferCollectionConstraints constraints = {};
+        constraints.usage.vulkan = fuchsia::sysmem::vulkanUsageColorAttachment |
+                                   fuchsia::sysmem::vulkanUsageTransferSrc |
+                                   fuchsia::sysmem::vulkanUsageTransferDst |
+                                   fuchsia::sysmem::vulkanUsageSampled;
+        constraints.min_buffer_count_for_camping = 1;
+        constraints.has_buffer_memory_constraints = true;
+        fuchsia::sysmem::BufferMemoryConstraints& buffer_constraints =
+            constraints.buffer_memory_constraints;
+        buffer_constraints.min_size_bytes = pImageInfo->extent.width * pImageInfo->extent.height * 4;
+        buffer_constraints.max_size_bytes = 0xffffffff;
+        buffer_constraints.physically_contiguous_required = false;
+        buffer_constraints.secure_required = false;
+        buffer_constraints.secure_permitted = false;
+        constraints.image_format_constraints_count = 1;
+        fuchsia::sysmem::ImageFormatConstraints& image_constraints =
+            constraints.image_format_constraints[0];
+        image_constraints.pixel_format.type = fuchsia::sysmem::PixelFormatType::BGRA32;
+        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;
+
+        auto sysmem_collection = reinterpret_cast<fuchsia::sysmem::BufferCollectionSyncPtr*>(collection);
+        (*sysmem_collection)->SetConstraints(true, constraints);
+        return VK_SUCCESS;
+    }
 #endif
 
     VkResult on_vkAllocateMemory(
@@ -2618,6 +2715,10 @@
     std::vector<VkExtensionProperties> mHostDeviceExtensions;
 
     int mSyncDeviceFd = -1;
+
+#ifdef VK_USE_PLATFORM_FUCHSIA
+    fuchsia::sysmem::AllocatorSyncPtr mSysmemAllocator;
+#endif
 };
 
 ResourceTracker::ResourceTracker() : mImpl(new ResourceTracker::Impl()) { }
@@ -3038,6 +3139,34 @@
     return mImpl->on_vkImportSemaphoreFuchsiaHandleKHR(
         context, input_result, device, pInfo);
 }
+
+VkResult ResourceTracker::on_vkCreateBufferCollectionFUCHSIA(
+    void* context, VkResult input_result,
+    VkDevice device,
+    const VkBufferCollectionCreateInfoFUCHSIA* pInfo,
+    const VkAllocationCallbacks* pAllocator,
+    VkBufferCollectionFUCHSIA* pCollection) {
+    return mImpl->on_vkCreateBufferCollectionFUCHSIA(
+        context, input_result, device, pInfo, pAllocator, pCollection);
+}
+
+void ResourceTracker::on_vkDestroyBufferCollectionFUCHSIA(
+        void* context, VkResult input_result,
+        VkDevice device,
+        VkBufferCollectionFUCHSIA collection,
+        const VkAllocationCallbacks* pAllocator) {
+    return mImpl->on_vkDestroyBufferCollectionFUCHSIA(
+        context, input_result, device, collection, pAllocator);
+}
+
+VkResult ResourceTracker::on_vkSetBufferCollectionConstraintsFUCHSIA(
+        void* context, VkResult input_result,
+        VkDevice device,
+        VkBufferCollectionFUCHSIA collection,
+        const VkImageCreateInfo* pImageInfo) {
+    return mImpl->on_vkSetBufferCollectionConstraintsFUCHSIA(
+        context, input_result, device, collection, pImageInfo);
+}
 #endif
 
 VkResult ResourceTracker::on_vkGetAndroidHardwareBufferPropertiesANDROID(