vulkan: Handle vkGet/SetPrivateDataEXT on Android swapchains
authorJason Ekstrand <jason@jlekstrand.net>
Fri, 8 May 2020 07:06:26 +0000 (02:06 -0500)
committerMarge Bot <eric+marge@anholt.net>
Tue, 12 May 2020 18:01:48 +0000 (18:01 +0000)
There is an annoying spec corner on Android.  Because VkSwapchain is
implemented in the Vulkan loader on Android which may not know about
this extension, we have to handle it as a special case inside the
driver.  We only have to do this on Android and only for VkSwapchainKHR.

Acked-by: Samuel Pitoiset <samuel.pitoiset@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/4882>

src/vulkan/util/vk_object.c
src/vulkan/util/vk_object.h

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;
+   }
 }
index 8ae539bd55645a9f3fea6857d2d15cb8d22b3b46..7550b6a422bd1800a8f87025664b219a2bdf55b8 100644 (file)
@@ -26,6 +26,7 @@
 #include <vulkan/vulkan.h>
 #include <vulkan/vk_icd.h>
 
+#include "c11/threads.h"
 #include "util/macros.h"
 #include "util/sparse_array.h"
 
@@ -33,6 +34,8 @@
 extern "C" {
 #endif
 
+struct hash_table;
+
 struct vk_device;
 
 struct vk_object_base {
@@ -70,6 +73,11 @@ struct vk_device {
 
    /* For VK_EXT_private_data */
    uint32_t private_data_next_index;
+
+#ifdef ANDROID
+   mtx_t swapchain_private_mtx;
+   struct hash_table *swapchain_private;
+#endif
 };
 
 void vk_device_init(struct vk_device *device,