From: Jason Ekstrand Date: Fri, 8 May 2020 07:06:26 +0000 (-0500) Subject: vulkan: Handle vkGet/SetPrivateDataEXT on Android swapchains X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=3c87618d357a4f75a4f47b2638c8f89939fd6c61;p=mesa.git vulkan: Handle vkGet/SetPrivateDataEXT on Android swapchains 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 Part-of: --- diff --git a/src/vulkan/util/vk_object.c b/src/vulkan/util/vk_object.c index 789cf12b15c..25e42f397e3 100644 --- a/src/vulkan/util/vk_object.c +++ b/src/vulkan/util/vk_object.c @@ -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; + } } diff --git a/src/vulkan/util/vk_object.h b/src/vulkan/util/vk_object.h index 8ae539bd556..7550b6a422b 100644 --- a/src/vulkan/util/vk_object.h +++ b/src/vulkan/util/vk_object.h @@ -26,6 +26,7 @@ #include #include +#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,