Add implementation of the multi-image-format sysmem extension

Bug:62789

Change-Id: I1e9452fc3f7369c635598a12ea002cadcfd05248
Reviewed-on: https://fuchsia-review.googlesource.com/c/third_party/mesa/+/445976
Reviewed-by: John Bauman <jbauman@google.com>
diff --git a/src/intel/vulkan/anv_magma_buffer_collection.c b/src/intel/vulkan/anv_magma_buffer_collection.c
index 24546bf..6b67f30 100644
--- a/src/intel/vulkan/anv_magma_buffer_collection.c
+++ b/src/intel/vulkan/anv_magma_buffer_collection.c
@@ -23,14 +23,21 @@
 
 #include "anv_magma.h"
 #include "anv_private.h"
-#include "isl/isl.h"
 #include "magma_sysmem.h"
 #include "vk_util.h"
+#include "isl/isl.h"
 
 #if VK_USE_PLATFORM_FUCHSIA
 
+#define MAX_FORMAT_INDICES 128
+const uint32_t kMaxFormatIndices = MAX_FORMAT_INDICES;
+
 struct anv_buffer_collection {
    magma_buffer_collection_t buffer_collection;
+
+   magma_sysmem_buffer_constraints_t constraints;
+
+   uint32_t format_index_input_index_map[MAX_FORMAT_INDICES];
 };
 
 ANV_DEFINE_HANDLE_CASTS(anv_buffer_collection, VkBufferCollectionFUCHSIA)
@@ -56,7 +63,10 @@
    struct anv_buffer_collection* buffer_collection =
        vk_alloc2(&device->alloc, pAllocator, sizeof(*buffer_collection), 8,
                  VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
+
    buffer_collection->buffer_collection = magma_buffer_collection;
+   buffer_collection->constraints = 0;
+
    *pCollection = anv_buffer_collection_to_handle(buffer_collection);
 
    return VK_SUCCESS;
@@ -73,13 +83,18 @@
    if (status != MAGMA_STATUS_OK)
       return;
 
+   if (buffer_collection->constraints) {
+     magma_buffer_constraints_release(sysmem_connection, buffer_collection->constraints);
+   }
+
    magma_buffer_collection_release(sysmem_connection, buffer_collection->buffer_collection);
    vk_free2(&device->alloc, pAllocator, buffer_collection);
 }
 
 static VkResult get_image_format_constraints(
     VkDevice vk_device, VkFormat format, const VkImageCreateInfo* pImageInfo,
-    magma_image_format_constraints_t* image_constraints_out, isl_tiling_flags_t isl_tiling_flags)
+    magma_image_format_constraints_t* image_constraints_out, isl_tiling_flags_t isl_tiling_flags,
+    VkImageFormatConstraintsInfoFUCHSIA* format_constraints)
 {
    ANV_FROM_HANDLE(anv_device, device, vk_device);
 
@@ -100,7 +115,7 @@
       dim = ISL_SURF_DIM_2D;
       break;
    default:
-      return ANV_MAGMA_DRET(VK_ERROR_FORMAT_NOT_SUPPORTED);
+      return VK_ERROR_FORMAT_NOT_SUPPORTED;
    }
 
    struct isl_surf_init_info isl_surf_init_info = {
@@ -118,8 +133,10 @@
        .tiling_flags = isl_tiling_flags};
 
    struct isl_surf isl_surf;
-   if (!isl_surf_init_s(&device->isl_dev, &isl_surf, &isl_surf_init_info))
-      return ANV_MAGMA_DRET(VK_ERROR_FORMAT_NOT_SUPPORTED);
+   if (!isl_surf_init_s(&device->isl_dev, &isl_surf, &isl_surf_init_info)) {
+      intel_loge("get_image_format_constraints: isl_surf_init_s failed");
+      return VK_ERROR_FORMAT_NOT_SUPPORTED;
+   }
 
    assert(pImageInfo->extent.width);
    magma_image_format_constraints_t image_constraints = {.width = pImageInfo->extent.width,
@@ -145,7 +162,7 @@
       image_constraints.format_modifier = MAGMA_FORMAT_MODIFIER_INTEL_YF_TILED;
       break;
    default:
-      return ANV_MAGMA_DRET(VK_ERROR_FORMAT_NOT_SUPPORTED);
+      return VK_ERROR_FORMAT_NOT_SUPPORTED;
    }
 
    switch (format) {
@@ -171,8 +188,21 @@
    case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
       image_constraints.image_format = MAGMA_FORMAT_I420;
       break;
+   case VK_FORMAT_R8_UNORM:
+      image_constraints.image_format = MAGMA_FORMAT_R8;
+      if (format_constraints && format_constraints->sysmemFormat) {
+         if (format_constraints->sysmemFormat == MAGMA_FORMAT_L8) {
+            image_constraints.image_format = MAGMA_FORMAT_L8;
+         } else if (format_constraints->sysmemFormat != MAGMA_FORMAT_R8) {
+            return VK_ERROR_FORMAT_NOT_SUPPORTED;
+         }
+      }
+      break;
+   case VK_FORMAT_R8G8_UNORM:
+      image_constraints.image_format = MAGMA_FORMAT_R8G8;
+      break;
    default:
-      return ANV_MAGMA_DRET(VK_ERROR_FORMAT_NOT_SUPPORTED);
+      return VK_ERROR_FORMAT_NOT_SUPPORTED;
    }
 
    *image_constraints_out = image_constraints;
@@ -195,8 +225,7 @@
    uint32_t slot_count = 0;
    VkResult result;
 
-   const VkFormat kDefaultFormatList[] = {VK_FORMAT_B8G8R8A8_UNORM,
-                                          VK_FORMAT_R8G8B8A8_UNORM,
+   const VkFormat kDefaultFormatList[] = {VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM,
                                           VK_FORMAT_G8_B8R8_2PLANE_420_UNORM,
                                           VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM};
    magma_image_format_constraints_t image_constraints[3 * ARRAY_SIZE(kDefaultFormatList)];
@@ -206,6 +235,7 @@
 
    const VkFormat* format_list_to_try = &pImageInfo->format;
    uint32_t num_formats_to_try = 1;
+
    if (pImageInfo->format == VK_FORMAT_UNDEFINED) {
       format_list_to_try = kDefaultFormatList;
       num_formats_to_try = ARRAY_SIZE(kDefaultFormatList);
@@ -227,8 +257,9 @@
       // optimal formats do.
       assert(!(optimal_flags & ~linear_flags));
 #endif
-      result = get_image_format_constraints(vk_device, format, pImageInfo,
-                                            &image_constraints[slot_count], ISL_TILING_LINEAR_BIT);
+      result =
+          get_image_format_constraints(vk_device, format, pImageInfo,
+                                       &image_constraints[slot_count], ISL_TILING_LINEAR_BIT, NULL);
       if (result != VK_SUCCESS) {
          return result;
       }
@@ -238,14 +269,15 @@
           image_constraints[slot_count - 1].image_format != MAGMA_FORMAT_NV12 &&
           image_constraints[slot_count - 1].image_format != MAGMA_FORMAT_I420) {
          // We always support X tiled for scanout but there may be a more optimal tiling format.
-         result = get_image_format_constraints(vk_device, format, pImageInfo,
-                                               &image_constraints[slot_count], ISL_TILING_X_BIT);
+         result = get_image_format_constraints(
+             vk_device, format, pImageInfo, &image_constraints[slot_count], ISL_TILING_X_BIT, NULL);
          if (result == VK_SUCCESS) {
             assert(image_constraints[slot_count].has_format_modifier);
             slot_count++;
             assert(slot_count < ARRAY_SIZE(image_constraints));
-            result = get_image_format_constraints(
-                vk_device, format, pImageInfo, &image_constraints[slot_count], ISL_TILING_ANY_MASK);
+            result = get_image_format_constraints(vk_device, format, pImageInfo,
+                                                  &image_constraints[slot_count],
+                                                  ISL_TILING_ANY_MASK, NULL);
             if (result == VK_SUCCESS) {
                assert(image_constraints[slot_count].has_format_modifier);
                if (image_constraints[slot_count].format_modifier !=
@@ -365,6 +397,374 @@
    return VK_SUCCESS;
 }
 
+VkFormat sysmem_to_vk_format(uint32_t sysmem_format)
+{
+   switch (sysmem_format) {
+   case MAGMA_FORMAT_BGRA32:
+      return VK_FORMAT_B8G8R8A8_UNORM;
+   case MAGMA_FORMAT_R8G8B8A8:
+      return VK_FORMAT_R8G8B8A8_UNORM;
+   case MAGMA_FORMAT_NV12:
+      return VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
+   case MAGMA_FORMAT_I420:
+      return VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM;
+   case MAGMA_FORMAT_L8:
+   case MAGMA_FORMAT_R8:
+      return VK_FORMAT_R8_UNORM;
+   case MAGMA_FORMAT_R8G8:
+      return VK_FORMAT_R8G8_UNORM;
+   default:
+      return VK_FORMAT_UNDEFINED;
+   }
+}
+
+VkResult
+anv_GetBufferCollectionProperties2FUCHSIA(VkDevice vk_device,
+                                          VkBufferCollectionFUCHSIA vk_collection,
+                                          VkBufferCollectionProperties2FUCHSIA* pProperties)
+{
+   ANV_FROM_HANDLE(anv_device, device, vk_device);
+   ANV_FROM_HANDLE(anv_buffer_collection, buffer_collection, vk_collection);
+
+   magma_sysmem_connection_t sysmem_connection;
+   magma_status_t status = AnvMagmaGetSysmemConnection(device->connection, &sysmem_connection);
+   if (status != MAGMA_STATUS_OK)
+      return ANV_MAGMA_DRET(VK_ERROR_DEVICE_LOST);
+
+   magma_buffer_format_description_t description;
+   status = magma_sysmem_get_description_from_collection(
+       sysmem_connection, buffer_collection->buffer_collection, &description);
+   if (status != MAGMA_STATUS_OK)
+      return ANV_MAGMA_DRET(VK_ERROR_OUT_OF_HOST_MEMORY);
+
+   uint32_t count;
+   status = magma_get_buffer_count(description, &count);
+   if (status != MAGMA_STATUS_OK) {
+      magma_buffer_format_description_release(description);
+      return ANV_MAGMA_DRET(VK_ERROR_OUT_OF_HOST_MEMORY);
+   }
+
+   uint32_t sysmem_format;
+   status = magma_get_buffer_format(description, &sysmem_format);
+   if (status != MAGMA_STATUS_OK) {
+      magma_buffer_format_description_release(description);
+      return ANV_MAGMA_DRET(VK_ERROR_OUT_OF_HOST_MEMORY);
+   }
+
+   pProperties->sysmemFormat = sysmem_format;
+
+   magma_bool_t has_format_modifier;
+   uint64_t format_modifier = 0;
+   status = magma_get_buffer_format_modifier(description, &has_format_modifier, &format_modifier);
+   if (status != MAGMA_STATUS_OK) {
+      magma_buffer_format_description_release(description);
+      return ANV_MAGMA_DRET(VK_ERROR_OUT_OF_HOST_MEMORY);
+   }
+
+   uint32_t color_space = MAGMA_COLORSPACE_INVALID;
+   magma_get_buffer_color_space(description, &color_space);
+   // Colorspace may be invalid for non-images, so ignore error.
+
+   pProperties->colorSpace.colorSpace = color_space;
+   pProperties->samplerYcbcrConversionComponents.r = VK_COMPONENT_SWIZZLE_IDENTITY;
+   pProperties->samplerYcbcrConversionComponents.g = VK_COMPONENT_SWIZZLE_IDENTITY;
+   pProperties->samplerYcbcrConversionComponents.b = VK_COMPONENT_SWIZZLE_IDENTITY;
+   pProperties->samplerYcbcrConversionComponents.a = VK_COMPONENT_SWIZZLE_IDENTITY;
+
+   pProperties->suggestedYcbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_NARROW;
+   pProperties->suggestedXChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN;
+   pProperties->suggestedYChromaOffset = VK_CHROMA_LOCATION_MIDPOINT;
+
+   switch (color_space) {
+   case MAGMA_COLORSPACE_REC601_NTSC:
+   case MAGMA_COLORSPACE_REC601_PAL:
+      pProperties->suggestedYcbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601;
+      break;
+
+   case MAGMA_COLORSPACE_REC601_NTSC_FULL_RANGE:
+   case MAGMA_COLORSPACE_REC601_PAL_FULL_RANGE:
+      pProperties->suggestedYcbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601;
+      pProperties->suggestedYcbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_FULL;
+      break;
+
+   case MAGMA_COLORSPACE_REC709:
+      pProperties->suggestedYcbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709;
+      break;
+
+   case MAGMA_COLORSPACE_REC2020:
+      pProperties->suggestedYcbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020;
+      break;
+
+   case MAGMA_COLORSPACE_SRGB:
+      pProperties->suggestedYcbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY;
+      pProperties->suggestedYcbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_FULL;
+      break;
+
+   default:
+      pProperties->suggestedYcbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY;
+      pProperties->suggestedYcbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_FULL;
+      break;
+   }
+
+   pProperties->createInfoIndex = 0;
+
+   if (buffer_collection->constraints) {
+      magma_bool_t format_valid[kMaxFormatIndices];
+      status = magma_get_description_format_index(sysmem_connection, description,
+                                                  buffer_collection->constraints, format_valid,
+                                                  kMaxFormatIndices);
+      if (status != MAGMA_STATUS_OK) {
+         magma_buffer_format_description_release(description);
+         return ANV_MAGMA_DRET(VK_ERROR_OUT_OF_HOST_MEMORY);
+      }
+
+      // Choose the first valid format for now.
+      for (uint32_t i = 0; i < kMaxFormatIndices; i++) {
+         if (format_valid[i]) {
+            pProperties->createInfoIndex = buffer_collection->format_index_input_index_map[i];
+            break;
+         }
+      }
+   }
+
+   if (!has_format_modifier) {
+      format_modifier = MAGMA_FORMAT_MODIFIER_LINEAR;
+   }
+
+   {
+      VkFormat format = sysmem_to_vk_format(sysmem_format);
+      const struct anv_physical_device* physical_device = device->physical;
+      const struct gen_device_info* devinfo = &physical_device->info;
+      const struct anv_format* anv_format = anv_get_format(format);
+      if (has_format_modifier) {
+         pProperties->formatFeatures =
+             anv_get_image_format_features(devinfo, format, anv_format, VK_IMAGE_TILING_OPTIMAL);
+      } else {
+         pProperties->formatFeatures =
+             anv_get_image_format_features(devinfo, format, anv_format, VK_IMAGE_TILING_LINEAR);
+      }
+   }
+
+   magma_buffer_format_description_release(description);
+
+   pProperties->bufferCount = count;
+
+   if (pProperties->bufferCount < 1) {
+      pProperties->memoryTypeBits = 0u;
+   } else {
+      struct anv_physical_device* pdevice = device->physical;
+      // All memory types supported.
+      pProperties->memoryTypeBits = (1ull << pdevice->memory.type_count) - 1;
+   }
+
+   return VK_SUCCESS;
+}
+
+VkResult anv_SetBufferCollectionImageConstraintsFUCHSIA(
+    VkDevice vk_device, VkBufferCollectionFUCHSIA vk_collection,
+    const VkImageConstraintsInfoFUCHSIA* pImageConstraintsInfo)
+{
+   ANV_FROM_HANDLE(anv_device, device, vk_device);
+   ANV_FROM_HANDLE(anv_buffer_collection, collection, vk_collection);
+
+   // Can't set constraints twice.
+   if (collection->constraints)
+      return ANV_MAGMA_DRET(VK_ERROR_INITIALIZATION_FAILED);
+
+   magma_sysmem_connection_t sysmem_connection;
+   magma_status_t status = AnvMagmaGetSysmemConnection(device->connection, &sysmem_connection);
+   if (status != MAGMA_STATUS_OK)
+      return ANV_MAGMA_DRET(VK_ERROR_DEVICE_LOST);
+
+   if (pImageConstraintsInfo->createInfoCount < 1) {
+      assert(!(pImageConstraintsInfo->createInfoCount < 1));
+      return ANV_MAGMA_DRET(VK_ERROR_FORMAT_NOT_SUPPORTED);
+   }
+
+   const bool have_format_constraints = (pImageConstraintsInfo->pFormatConstraints != NULL);
+
+   // Secure formats not supported.
+   for (uint32_t i = 0; i < pImageConstraintsInfo->createInfoCount; ++i) {
+      bool secure_required =
+          (pImageConstraintsInfo->pCreateInfos[i].flags & VK_IMAGE_CREATE_PROTECTED_BIT);
+
+      const VkImageFormatConstraintsInfoFUCHSIA* format_constraints =
+          have_format_constraints ? &pImageConstraintsInfo->pFormatConstraints[i] : NULL;
+
+      bool this_secure_optional =
+          have_format_constraints && (pImageConstraintsInfo->pFormatConstraints[i].flags &
+                                      VK_IMAGE_FORMAT_CONSTRAINTS_PROTECTED_OPTIONAL_FUCHSIA);
+
+      if (secure_required || this_secure_optional) {
+         assert(!(secure_required || this_secure_optional));
+         return ANV_MAGMA_DRET(VK_ERROR_FORMAT_NOT_SUPPORTED);
+      }
+   }
+
+   magma_sysmem_buffer_constraints_t constraints;
+
+   // Create the buffer constraints.
+   {
+      magma_buffer_format_constraints_t format_constraints = {
+          .count = pImageConstraintsInfo->minBufferCount,
+          .usage = 0,
+          .secure_permitted = false,
+          .secure_required = false,
+          .ram_domain_supported = true,
+          .cpu_domain_supported = true,
+          .min_size_bytes = 0,
+      };
+
+      status =
+          magma_buffer_constraints_create(sysmem_connection, &format_constraints, &constraints);
+      if (status != MAGMA_STATUS_OK)
+         return ANV_MAGMA_DRET(VK_ERROR_OUT_OF_HOST_MEMORY);
+   }
+
+   // Add additional constraints.
+   {
+      magma_buffer_format_additional_constraints_t additional = {
+          .min_buffer_count_for_camping = pImageConstraintsInfo->minBufferCountForCamping,
+          .min_buffer_count_for_shared_slack = pImageConstraintsInfo->minBufferCountForSharedSlack,
+          .min_buffer_count_for_dedicated_slack =
+              pImageConstraintsInfo->minBufferCountForDedicatedSlack,
+          .max_buffer_count = pImageConstraintsInfo->maxBufferCount};
+
+      status = magma_buffer_constraints_add_additional(sysmem_connection, constraints, &additional);
+      if (status != MAGMA_STATUS_OK) {
+         magma_buffer_constraints_release(sysmem_connection, constraints);
+         return ANV_MAGMA_DRET(VK_ERROR_OUT_OF_HOST_MEMORY);
+      }
+   }
+
+   uint32_t format_index = 0;
+
+   // Set format slots for each image info.
+   for (uint32_t i = 0; i < pImageConstraintsInfo->createInfoCount; ++i) {
+      const VkImageCreateInfo* pCreateInfo = &pImageConstraintsInfo->pCreateInfos[i];
+      VkFormat format = pCreateInfo->format;
+
+      const struct anv_physical_device* physical_device = device->physical;
+      const struct gen_device_info* devinfo = &physical_device->info;
+      const struct anv_format* anv_format = anv_get_format(format);
+      const VkFormatFeatureFlags linear_flags =
+          anv_get_image_format_features(devinfo, format, anv_format, VK_IMAGE_TILING_LINEAR);
+      const VkFormatFeatureFlags optimal_flags =
+          anv_get_image_format_features(devinfo, format, anv_format, VK_IMAGE_TILING_OPTIMAL);
+
+      const VkImageFormatConstraintsInfoFUCHSIA* format_constraints =
+          have_format_constraints ? &pImageConstraintsInfo->pFormatConstraints[i] : NULL;
+
+      const uint32_t colorSpaceCount = format_constraints ? format_constraints->colorSpaceCount : 0;
+      uint32_t color_spaces[colorSpaceCount];
+
+      for (uint32_t j = 0; j < colorSpaceCount; ++j) {
+         color_spaces[j] = format_constraints->pColorSpaces[j].colorSpace;
+      }
+
+      enum { SLOT0_LINEAR, SLOT1_X_TILED, SLOT2_TILED };
+      const uint32_t kSlotCount = 3;
+      magma_image_format_constraints_t image_constraints[kSlotCount];
+      bool image_constraints_valid[kSlotCount];
+
+      status = get_image_format_constraints(vk_device, format, pCreateInfo,
+                                            &image_constraints[SLOT0_LINEAR], ISL_TILING_LINEAR_BIT,
+                                            format_constraints);
+      if (status != VK_SUCCESS)
+         continue;
+
+      // Sysmem can't handle certain formats tiled, so don't attempt it.
+      bool skip_optimal = (pCreateInfo->tiling == VK_IMAGE_TILING_LINEAR) ||
+                          (image_constraints[SLOT0_LINEAR].image_format == MAGMA_FORMAT_NV12) ||
+                          (image_constraints[SLOT0_LINEAR].image_format == MAGMA_FORMAT_I420) ||
+                          (image_constraints[SLOT0_LINEAR].image_format == MAGMA_FORMAT_L8) ||
+                          (image_constraints[SLOT0_LINEAR].image_format == MAGMA_FORMAT_R8) ||
+                          (image_constraints[SLOT0_LINEAR].image_format == MAGMA_FORMAT_R8G8);
+
+      image_constraints_valid[SLOT0_LINEAR] =
+          !format_constraints || !(~linear_flags & format_constraints->requiredFormatFeatures);
+
+      if (skip_optimal) {
+         image_constraints_valid[SLOT1_X_TILED] = false;
+      } else {
+         image_constraints_valid[SLOT1_X_TILED] =
+             !format_constraints || !(~optimal_flags & format_constraints->requiredFormatFeatures);
+      }
+
+      image_constraints_valid[SLOT2_TILED] = image_constraints_valid[SLOT1_X_TILED];
+
+      for (uint32_t slot = 0; slot < kSlotCount; slot++) {
+         if (!image_constraints_valid[slot])
+            continue;
+
+         switch (slot) {
+         case SLOT0_LINEAR:
+            // Image constraints already initialized.
+            break;
+         case SLOT1_X_TILED:
+            status = get_image_format_constraints(vk_device, format, pCreateInfo,
+                                                  &image_constraints[SLOT1_X_TILED],
+                                                  ISL_TILING_X_BIT, format_constraints);
+            break;
+         case SLOT2_TILED:
+            status = get_image_format_constraints(vk_device, format, pCreateInfo,
+                                                  &image_constraints[SLOT2_TILED],
+                                                  ISL_TILING_ANY_MASK, format_constraints);
+            break;
+         default:
+            assert(false);
+         }
+
+         if (status != VK_SUCCESS)
+            continue;
+
+         // Currently every vulkan format maps to only 1 sysmem format, so ensure the client is
+         // using the same format.
+         if (format_constraints && format_constraints->sysmemFormat &&
+             (format_constraints->sysmemFormat != image_constraints[slot].image_format)) {
+            continue;
+         }
+
+         collection->format_index_input_index_map[format_index] = i;
+
+         status = magma_buffer_constraints_set_format(sysmem_connection, constraints, format_index,
+                                                      &image_constraints[slot]);
+         if (status != MAGMA_STATUS_OK) {
+            magma_buffer_constraints_release(sysmem_connection, constraints);
+            return ANV_MAGMA_DRET(VK_ERROR_FORMAT_NOT_SUPPORTED);
+         }
+
+         if (colorSpaceCount) {
+            magma_buffer_constraints_set_colorspaces(sysmem_connection, constraints, format_index,
+                                                     colorSpaceCount, color_spaces);
+         }
+
+         format_index += 1;
+         if (format_index >= kMaxFormatIndices) {
+            assert(!(format_index >= kMaxFormatIndices));
+            magma_buffer_constraints_release(sysmem_connection, constraints);
+            return ANV_MAGMA_DRET(VK_ERROR_OUT_OF_HOST_MEMORY);
+         }
+      }
+   }
+
+   if (format_index == 0) {
+      magma_buffer_constraints_release(sysmem_connection, constraints);
+      return ANV_MAGMA_DRET(VK_ERROR_FORMAT_NOT_SUPPORTED);
+   }
+
+   status = magma_buffer_collection_set_constraints(sysmem_connection,
+                                                    collection->buffer_collection, constraints);
+   if (status != MAGMA_STATUS_OK) {
+      magma_buffer_constraints_release(sysmem_connection, constraints);
+      return ANV_MAGMA_DRET(VK_ERROR_FORMAT_NOT_SUPPORTED);
+   }
+
+   collection->constraints = constraints;
+
+   return VK_SUCCESS;
+}
+
 // Takes ownership of the buffer format description.
 static VkResult anv_image_params_from_description(
     magma_buffer_format_description_t description, uint32_t width, uint32_t height,
diff --git a/src/vulkan/registry/vk.xml b/src/vulkan/registry/vk.xml
index 5452635..08fa87d 100644
--- a/src/vulkan/registry/vk.xml
+++ b/src/vulkan/registry/vk.xml
@@ -345,6 +345,7 @@
         <type                                             category="bitmask">typedef <type>VkFlags</type> <name>VkPipelineRasterizationDepthClipStateCreateFlagsEXT</name>;</type>
         <type requires="VkSwapchainImageUsageFlagBitsANDROID" category="bitmask">typedef <type>VkFlags</type> <name>VkSwapchainImageUsageFlagsANDROID</name>;</type>
         <type requires="VkToolPurposeFlagBitsEXT"         category="bitmask">typedef <type>VkFlags</type> <name>VkToolPurposeFlagsEXT</name>;</type>
+        <type requires="VkImageFormatConstraintsFlagBitsFUCHSIA"     category="bitmask">typedef <type>VkFlags</type> <name>VkImageFormatConstraintsFlagsFUCHSIA</name>;</type>
 
             <comment>Types which can be void pointers or class pointers, selected at compile time</comment>
         <type category="handle"><type>VK_DEFINE_HANDLE</type>(<name>VkInstance</name>)</type>
@@ -537,6 +538,7 @@
         <type name="VkPipelineCompilerControlFlagBitsAMD" category="enum"/>
         <type name="VkShaderCorePropertiesFlagBitsAMD" category="enum"/>
         <type name="VkToolPurposeFlagBitsEXT" category="enum"/>
+        <type name="VkImageFormatConstraintsFlagBitsFUCHSIA" category="enum"/>
 
             <comment>WSI extensions</comment>
         <type name="VkColorSpaceKHR" category="enum"/>
@@ -2252,13 +2254,54 @@
             <member><type>uint32_t</type>                         <name>memoryTypeBits</name></member>
             <member><type>uint32_t</type>                         <name>count</name></member>
         </type>
+        <type category="struct" name="VkBufferCollectionProperties2FUCHSIA">
+            <member values="VK_STRUCTURE_TYPE_BUFFER_COLLECTION_PROPERTIES2_FUCHSIA"><type>VkStructureType</type> <name>sType</name></member>
+            <member><type>void</type>*                            <name>pNext</name></member>
+            <member><type>uint32_t</type>                         <name>memoryTypeBits</name></member>
+            <member><type>uint32_t</type>                         <name>bufferCount</name></member>
+            <member><type>uint32_t</type>                         <name>createInfoIndex</name></member>
+            <member><type>uint64_t</type>                         <name>sysmemFormat</name></member>
+            <member><type>VkFormatFeatureFlags</type>             <name>formatFeatures</name></member>
+            <member><type>VkSysmemColorSpaceFUCHSIA</type>        <name>colorSpace</name></member>
+            <member><type>VkComponentMapping</type>               <name>samplerYcbcrConversionComponents</name></member>
+            <member><type>VkSamplerYcbcrModelConversion</type>    <name>suggestedYcbcrModel</name></member>
+            <member><type>VkSamplerYcbcrRange</type>              <name>suggestedYcbcrRange</name></member>
+            <member><type>VkChromaLocation</type>                 <name>suggestedXChromaOffset</name></member>
+            <member><type>VkChromaLocation</type>                 <name>suggestedYChromaOffset</name></member>
+        </type>
         <type category="struct" name="VkBufferConstraintsInfoFUCHSIA">
             <member values="VK_STRUCTURE_TYPE_BUFFER_CONSTRAINTS_INFO_FUCHSIA"><type>VkStructureType</type> <name>sType</name></member>
             <member>const <type>void</type>*                      <name>pNext</name></member>
             <member>const <type>VkBufferCreateInfo</type>*        <name>pBufferCreateInfo</name></member>
-            <member><type>VkFormatFeatureFlags</type>             <name>requiredFormatFeatures</name></member>
+            <member optional="true"> <type>VkFormatFeatureFlags</type>             <name>requiredFormatFeatures</name></member>
             <member><type>uint32_t</type>                         <name>minCount</name></member>
         </type>
+        <type category="struct" name="VkSysmemColorSpaceFUCHSIA">
+            <member values="VK_STRUCTURE_TYPE_SYSMEM_COLOR_SPACE_FUCHSIA"><type>VkStructureType</type> <name>sType</name></member>
+            <member>const <type>void</type>*                     <name>pNext</name></member>
+            <member><type>uint32_t</type>                        <name>colorSpace</name></member>
+        </type>
+        <type category="struct" name="VkImageFormatConstraintsInfoFUCHSIA">
+            <member values="VK_STRUCTURE_TYPE_IMAGE_FORMAT_CONSTRAINTS_INFO_FUCHSIA"><type>VkStructureType</type> <name>sType</name></member>
+            <member>const <type>void</type>*                     <name>pNext</name></member>
+            <member optional="true"><type>VkFormatFeatureFlags</type>            <name>requiredFormatFeatures</name></member>
+            <member optional="true"><type>VkImageFormatConstraintsFlagsFUCHSIA</type>       <name>flags</name></member>
+            <member><type>uint64_t</type>                        <name>sysmemFormat</name></member>
+            <member><type>uint32_t</type>                        <name>colorSpaceCount</name></member>
+            <member optional="true">const <type>VkSysmemColorSpaceFUCHSIA</type>*      <name>pColorSpaces</name></member>
+        </type>
+        <type category="struct" name="VkImageConstraintsInfoFUCHSIA">
+            <member values="VK_STRUCTURE_TYPE_IMAGE_CONSTRAINTS_INFO_FUCHSIA"><type>VkStructureType</type> <name>sType</name></member>
+            <member>const <type>void</type>*                     <name>pNext</name></member>
+            <member><type>uint32_t</type>                        <name>createInfoCount</name></member>
+            <member len="createInfoCount">const <type>VkImageCreateInfo</type>*  <name>pCreateInfos</name></member>
+            <member len="createInfoCount" optional="true">const <type>VkImageFormatConstraintsInfoFUCHSIA</type>* <name>pFormatConstraints</name></member>
+            <member><type>uint32_t</type>                        <name>minBufferCount</name></member>
+            <member><type>uint32_t</type>                        <name>maxBufferCount</name></member>
+            <member><type>uint32_t</type>                        <name>minBufferCountForCamping</name></member>
+            <member><type>uint32_t</type>                        <name>minBufferCountForDedicatedSlack</name></member>
+            <member><type>uint32_t</type>                        <name>minBufferCountForSharedSlack</name></member>
+        </type>
         <type category="struct" name="VkWin32KeyedMutexAcquireReleaseInfoKHR" structextends="VkSubmitInfo">
             <member values="VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
             <member>const <type>void</type>*                      <name>pNext</name></member>
@@ -5926,6 +5969,13 @@
         <enum bitpos="3"     name="VK_TOOL_PURPOSE_ADDITIONAL_FEATURES_BIT_EXT"/>
         <enum bitpos="4"     name="VK_TOOL_PURPOSE_MODIFYING_FEATURES_BIT_EXT"/>
     </enums>
+    <enums name="VkImageFormatConstraintsFlagBitsFUCHSIA" type="bitmask">
+        <enum bitpos="0"    name="VK_IMAGE_FORMAT_CONSTRAINTS_CPU_READ_RARELY_FUCHSIA"/>
+        <enum bitpos="1"    name="VK_IMAGE_FORMAT_CONSTRAINTS_CPU_READ_OFTEN_FUCHSIA"/>
+        <enum bitpos="2"    name="VK_IMAGE_FORMAT_CONSTRAINTS_CPU_WRITE_RARELY_FUCHSIA"/>
+        <enum bitpos="3"    name="VK_IMAGE_FORMAT_CONSTRAINTS_CPU_WRITE_OFTEN_FUCHSIA"/>
+        <enum bitpos="4"    name="VK_IMAGE_FORMAT_CONSTRAINTS_PROTECTED_OPTIONAL_FUCHSIA"/>
+    </enums>
 
     <commands comment="Vulkan command definitions">
         <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_INITIALIZATION_FAILED,VK_ERROR_LAYER_NOT_PRESENT,VK_ERROR_EXTENSION_NOT_PRESENT,VK_ERROR_INCOMPATIBLE_DRIVER">
@@ -7106,6 +7156,12 @@
             <param>const <type>VkImageCreateInfo</type>* <name>pImageInfo</name></param>
         </command>
         <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+            <proto><type>VkResult</type> <name>vkSetBufferCollectionImageConstraintsFUCHSIA</name></proto>
+            <param><type>VkDevice</type> <name>device</name></param>
+            <param><type>VkBufferCollectionFUCHSIA</type> <name>collection</name></param>
+            <param>const <type>VkImageConstraintsInfoFUCHSIA</type>* <name>pImageConstraintsInfo</name></param>
+        </command>
+        <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
             <proto><type>VkResult</type> <name>vkSetBufferCollectionBufferConstraintsFUCHSIA</name></proto>
             <param><type>VkDevice</type> <name>device</name></param>
             <param><type>VkBufferCollectionFUCHSIA</type> <name>collection</name></param>
@@ -7123,6 +7179,12 @@
             <param><type>VkBufferCollectionFUCHSIA</type> <name>collection</name></param>
             <param><type>VkBufferCollectionPropertiesFUCHSIA</type>* <name>pProperties</name></param>
         </command>
+        <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+            <proto><type>VkResult</type> <name>vkGetBufferCollectionProperties2FUCHSIA</name></proto>
+            <param><type>VkDevice</type> <name>device</name></param>
+            <param><type>VkBufferCollectionFUCHSIA</type> <name>collection</name></param>
+            <param><type>VkBufferCollectionProperties2FUCHSIA</type>* <name>pProperties</name></param>
+        </command>
         <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_NATIVE_WINDOW_IN_USE_KHR">
             <proto><type>VkResult</type> <name>vkCreateStreamDescriptorSurfaceGGP</name></proto>
             <param><type>VkInstance</type> <name>instance</name></param>
@@ -12577,7 +12639,7 @@
                 <enum bitpos="2"  extends="VkMemoryHeapFlagBits"            name="VK_MEMORY_HEAP_RESERVED_2_BIT_KHR"/>
             </require>
         </extension>
-        <extension name="VK_FUCHSIA_buffer_collection" number="1005" type="device" requires="VK_FUCHSIA_external_memory" author="FUCHSIA" contact="John Bauman @jbauman" supported="vulkan" platform="fuchsia">
+        <extension name="VK_FUCHSIA_buffer_collection" number="1005" type="device" requires="VK_FUCHSIA_external_memory,VK_KHR_sampler_ycbcr_conversion" author="FUCHSIA" contact="John Bauman @jbauman" supported="vulkan" platform="fuchsia">
             <require>
                 <enum value="1"                                         name="VK_FUCHSIA_BUFFER_COLLECTION_SPEC_VERSION"/>
                 <enum value="&quot;VK_FUCHSIA_buffer_collection&quot;"  name="VK_FUCHSIA_BUFFER_COLLECTION_EXTENSION_NAME"/>
@@ -12590,6 +12652,10 @@
                 <enum offset="6" extends="VkStructureType"              name="VK_STRUCTURE_TYPE_BUFFER_COLLECTION_PROPERTIES_FUCHSIA"/>
                 <enum offset="7" extends="VkStructureType"              name="VK_STRUCTURE_TYPE_BUFFER_CONSTRAINTS_INFO_FUCHSIA"/>
                 <enum offset="8" extends="VkStructureType"              name="VK_STRUCTURE_TYPE_BUFFER_COLLECTION_BUFFER_CREATE_INFO_FUCHSIA"/>
+                <enum offset="9" extends="VkStructureType"              name="VK_STRUCTURE_TYPE_IMAGE_CONSTRAINTS_INFO_FUCHSIA"/>
+                <enum offset="10" extends="VkStructureType"             name="VK_STRUCTURE_TYPE_IMAGE_FORMAT_CONSTRAINTS_INFO_FUCHSIA"/>
+                <enum offset="11" extends="VkStructureType"             name="VK_STRUCTURE_TYPE_BUFFER_COLLECTION_PROPERTIES2_FUCHSIA"/>
+                <enum offset="12" extends="VkStructureType"             name="VK_STRUCTURE_TYPE_SYSMEM_COLOR_SPACE_FUCHSIA"/>
                 <type name="VkBufferCollectionFUCHSIA"/>
                 <type name="VkBufferCollectionCreateInfoFUCHSIA"/>
                 <type name="VkFuchsiaImageFormatFUCHSIA"/>
@@ -12598,11 +12664,19 @@
                 <type name="VkBufferConstraintsInfoFUCHSIA"/>
                 <type name="VkBufferCollectionBufferCreateInfoFUCHSIA"/>
                 <type name="VkBufferCollectionPropertiesFUCHSIA"/>
+                <type name="VkBufferCollectionProperties2FUCHSIA"/>
+                <type name="VkImageFormatConstraintsFlagBitsFUCHSIA"/>
+                <type name="VkImageFormatConstraintsFlagsFUCHSIA"/>
+                <type name="VkSysmemColorSpaceFUCHSIA"/>
+                <type name="VkImageConstraintsInfoFUCHSIA"/>
+                <type name="VkImageFormatConstraintsInfoFUCHSIA"/>
                 <command name="vkCreateBufferCollectionFUCHSIA"/>
                 <command name="vkSetBufferCollectionConstraintsFUCHSIA"/>
                 <command name="vkSetBufferCollectionBufferConstraintsFUCHSIA"/>
+                <command name="vkSetBufferCollectionImageConstraintsFUCHSIA"/>
                 <command name="vkDestroyBufferCollectionFUCHSIA"/>
                 <command name="vkGetBufferCollectionPropertiesFUCHSIA"/>
+                <command name="vkGetBufferCollectionProperties2FUCHSIA"/>
             </require>
         </extension>
         <extension name="VK_FUCHSIA_external_memory" number="1006" type="device" requires="VK_KHR_external_memory_capabilities,VK_KHR_external_memory" author="FUCHSIA" contact="Craig Stout @cdotstout" supported="vulkan" platform="fuchsia">