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,