vulkan: Handle vkGet/SetPrivateDataEXT on Android swapchains
[mesa.git] / src / vulkan / util / vk_object.c
index 789cf12b15cf6888639da7a55122559a6bdd72f4..25e42f397e3aafbff3ac1cad0a9766d8197b7076 100644 (file)
@@ -24,6 +24,8 @@
 #include "vk_object.h"
 
 #include "vk_alloc.h"
+#include "util/hash_table.h"
+#include "util/ralloc.h"
 
 void
 vk_object_base_init(UNUSED struct vk_device *device,
@@ -54,11 +56,24 @@ vk_device_init(struct vk_device *device,
       device->alloc = *instance_alloc;
 
    p_atomic_set(&device->private_data_next_index, 0);
+
+#ifdef ANDROID
+   mtx_init(&device->swapchain_private_mtx, mtx_plain);
+   device->swapchain_private = NULL;
+#endif /* ANDROID */
 }
 
 void
 vk_device_finish(UNUSED struct vk_device *device)
 {
+#ifdef ANDROID
+   if (device->swapchain_private) {
+      hash_table_foreach(device->swapchain_private, entry)
+         util_sparse_array_finish(entry->data);
+      ralloc_free(device->swapchain_private);
+   }
+#endif /* ANDROID */
+
    vk_object_base_finish(&device->base);
 }
 
@@ -96,15 +111,77 @@ vk_private_data_slot_destroy(struct vk_device *device,
    vk_free2(&device->alloc, pAllocator, slot);
 }
 
-static uint64_t *
-vk_object_base_private_data(VkObjectType objectType,
+#ifdef ANDROID
+static VkResult
+get_swapchain_private_data_locked(struct vk_device *device,
+                                  uint64_t objectHandle,
+                                  struct vk_private_data_slot *slot,
+                                  uint64_t **private_data)
+{
+   if (unlikely(device->swapchain_private == NULL)) {
+      /* Even though VkSwapchain is a non-dispatchable object, we know a
+       * priori that Android swapchains are actually pointers so we can use
+       * the pointer hash table for them.
+       */
+      device->swapchain_private = _mesa_pointer_hash_table_create(NULL);
+      if (device->swapchain_private == NULL)
+         return VK_ERROR_OUT_OF_HOST_MEMORY;
+   }
+
+   struct hash_entry *entry =
+      _mesa_hash_table_search(device->swapchain_private,
+                              (void *)(uintptr_t)objectHandle);
+   if (unlikely(entry == NULL)) {
+      struct util_sparse_array *swapchain_private =
+         ralloc(device->swapchain_private, struct util_sparse_array);
+      util_sparse_array_init(swapchain_private, sizeof(uint64_t), 8);
+
+      entry = _mesa_hash_table_insert(device->swapchain_private,
+                                      (void *)(uintptr_t)objectHandle,
+                                      swapchain_private);
+      if (entry == NULL)
+         return VK_ERROR_OUT_OF_HOST_MEMORY;
+   }
+
+   struct util_sparse_array *swapchain_private = entry->data;
+   *private_data = util_sparse_array_get(swapchain_private, slot->index);
+
+   return VK_SUCCESS;
+}
+#endif /* ANDROID */
+
+static VkResult
+vk_object_base_private_data(struct vk_device *device,
+                            VkObjectType objectType,
                             uint64_t objectHandle,
-                            VkPrivateDataSlotEXT privateDataSlot)
+                            VkPrivateDataSlotEXT privateDataSlot,
+                            uint64_t **private_data)
 {
    VK_FROM_HANDLE(vk_private_data_slot, slot, privateDataSlot);
+
+#ifdef ANDROID
+   /* There is an annoying spec corner here on Android.  Because WSI is
+    * implemented in the Vulkan loader which doesn't know about the
+    * VK_EXT_private_data extension, we have to handle VkSwapchainKHR in the
+    * driver as a special case.  On future versions of Android where the
+    * loader does understand VK_EXT_private_data, we'll never see a
+    * vkGet/SetPrivateDataEXT call on a swapchain because the loader will
+    * handle it.
+    */
+   if (objectType == VK_OBJECT_TYPE_SWAPCHAIN_KHR) {
+      mtx_lock(&device->swapchain_private_mtx);
+      VkResult result = get_swapchain_private_data_locked(device, objectHandle,
+                                                          slot, private_data);
+      mtx_unlock(&device->swapchain_private_mtx);
+      return result;
+   }
+#endif /* ANDROID */
+
    struct vk_object_base *obj =
       vk_object_base_from_u64_handle(objectHandle, objectType);
-   return util_sparse_array_get(&obj->private_data, slot->index);
+   *private_data = util_sparse_array_get(&obj->private_data, slot->index);
+
+   return VK_SUCCESS;
 }
 
 VkResult
@@ -114,8 +191,14 @@ vk_object_base_set_private_data(struct vk_device *device,
                                 VkPrivateDataSlotEXT privateDataSlot,
                                 uint64_t data)
 {
-   uint64_t *private_data =
-      vk_object_base_private_data(objectType, objectHandle, privateDataSlot);
+   uint64_t *private_data;
+   VkResult result = vk_object_base_private_data(device,
+                                                 objectType, objectHandle,
+                                                 privateDataSlot,
+                                                 &private_data);
+   if (unlikely(result != VK_SUCCESS))
+      return result;
+
    *private_data = data;
    return VK_SUCCESS;
 }
@@ -127,7 +210,14 @@ vk_object_base_get_private_data(struct vk_device *device,
                                 VkPrivateDataSlotEXT privateDataSlot,
                                 uint64_t *pData)
 {
-   uint64_t *private_data =
-      vk_object_base_private_data(objectType, objectHandle, privateDataSlot);
-   *pData = *private_data;
+   uint64_t *private_data;
+   VkResult result = vk_object_base_private_data(device,
+                                                 objectType, objectHandle,
+                                                 privateDataSlot,
+                                                 &private_data);
+   if (likely(result == VK_SUCCESS)) {
+      *pData = *private_data;
+   } else {
+      *pData = 0;
+   }
 }