diff options
author | Yiwei Zhang <zzyiwei@chromium.org> | 2021-04-28 23:03:10 +0000 |
---|---|---|
committer | Marge Bot <eric+marge@anholt.net> | 2021-04-29 17:33:52 +0000 |
commit | 96ec6b3d8fa828bd4bc58cd2183797953caaa405 (patch) | |
tree | f901bb65003e9e216575b84728e890d4c9e603a8 | |
parent | 174fca5498e8fcaf471a9692c1fcaa3945417429 (diff) |
venus: handle wsi image queue ownership transfer for Android
1. pre-allocate command pools at device creation if anb enabled
2. force VK_SHARING_MODE_CONCURRENT for wsi image if necessary
3. pre-allocate and record command buffers at android wsi image creation
4. transfer in the ownership at vkAcquireImageANDROID
5. transfer out the ownership at vkQueueSignalReleaseImageANDROID
Signed-off-by: Yiwei Zhang <zzyiwei@chromium.org>
Reviewed-by: Chia-I Wu <olvaffe@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/10335>
-rw-r--r-- | src/virtio/vulkan/vn_android.c | 179 | ||||
-rw-r--r-- | src/virtio/vulkan/vn_android.h | 35 | ||||
-rw-r--r-- | src/virtio/vulkan/vn_device.c | 9 | ||||
-rw-r--r-- | src/virtio/vulkan/vn_device.h | 2 | ||||
-rw-r--r-- | src/virtio/vulkan/vn_image.c | 152 | ||||
-rw-r--r-- | src/virtio/vulkan/vn_image.h | 18 |
6 files changed, 388 insertions, 7 deletions
diff --git a/src/virtio/vulkan/vn_android.c b/src/virtio/vulkan/vn_android.c index fc14da62ce2..523b1a1fdae 100644 --- a/src/virtio/vulkan/vn_android.c +++ b/src/virtio/vulkan/vn_android.c @@ -9,7 +9,6 @@ */ #include "vn_android.h" -#include "vn_common.h" #include <drm/drm_fourcc.h> #include <hardware/hwvulkan.h> @@ -189,12 +188,36 @@ vn_image_from_anb(struct vn_device *dev, VkImageCreateInfo local_image_info = *image_info; local_image_info.pNext = &drm_mod_info; local_image_info.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT; + + /* Force VK_SHARING_MODE_CONCURRENT if necessary. + * For physical devices supporting multiple queue families, if a swapchain is + * created with exclusive mode, we must transfer the image ownership into the + * queue family of the present queue. However, there's no way to get that + * queue at the 1st acquire of the image. Thus, when multiple queue families + * are supported in a physical device, we include all queue families in the + * image create info along with VK_SHARING_MODE_CONCURRENT, which forces us + * to transfer the ownership into VK_QUEUE_FAMILY_IGNORED. Then if there's + * only one queue family, we can safely use queue family index 0. + */ + if (dev->physical_device->queue_family_count > 1) { + local_image_info.sharingMode = VK_SHARING_MODE_CONCURRENT; + local_image_info.queueFamilyIndexCount = + dev->physical_device->queue_family_count; + local_image_info.pQueueFamilyIndices = + dev->android_wsi->queue_family_indices; + } + /* encoder will strip the Android specific pNext structs */ result = vn_image_create(dev, &local_image_info, alloc, &img); if (result != VK_SUCCESS) goto fail; image = vn_image_to_handle(img); + + result = vn_image_android_wsi_init(dev, img, alloc); + if (result != VK_SUCCESS) + goto fail; + VkMemoryRequirements mem_req; vn_GetImageMemoryRequirements(device, image, &mem_req); if (!mem_req.memoryTypeBits) { @@ -272,9 +295,19 @@ fail: return vn_error(dev->instance, result); } +static bool +vn_is_queue_compatible_with_wsi(struct vn_queue *queue) +{ + static const int32_t compatible_flags = + VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT; + return compatible_flags & queue->device->physical_device + ->queue_family_properties[queue->family] + .queueFamilyProperties.queueFlags; +} + VkResult vn_AcquireImageANDROID(VkDevice device, - UNUSED VkImage image, + VkImage image, int nativeFenceFd, VkSemaphore semaphore, VkFence fence) @@ -285,6 +318,8 @@ vn_AcquireImageANDROID(VkDevice device, struct vn_device *dev = vn_device_from_handle(device); struct vn_semaphore *sem = vn_semaphore_from_handle(semaphore); struct vn_fence *fen = vn_fence_from_handle(fence); + struct vn_image *img = vn_image_from_handle(image); + struct vn_queue *queue = img->acquire_queue; if (nativeFenceFd >= 0) { int ret = sync_wait(nativeFenceFd, INT32_MAX); @@ -300,7 +335,41 @@ vn_AcquireImageANDROID(VkDevice device, if (fen) vn_fence_signal_wsi(dev, fen); - return VK_SUCCESS; + if (!queue) { + /* pick a compatible queue for the 1st acquire of this image */ + for (uint32_t i = 0; i < dev->queue_count; i++) { + if (vn_is_queue_compatible_with_wsi(&dev->queues[i])) { + queue = &dev->queues[i]; + break; + } + } + } + if (!queue) + return vn_error(dev->instance, VK_ERROR_UNKNOWN); + + const VkSubmitInfo submit_info = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .pNext = NULL, + .waitSemaphoreCount = 0, + .pWaitSemaphores = NULL, + .pWaitDstStageMask = NULL, + .commandBufferCount = 1, + .pCommandBuffers = + &img->ownership_cmds[queue->family].cmds[VN_IMAGE_OWNERSHIP_ACQUIRE], + .signalSemaphoreCount = 0, + .pSignalSemaphores = NULL, + }; + + VkResult result = vn_QueueSubmit(vn_queue_to_handle(queue), 1, + &submit_info, queue->wait_fence); + if (result != VK_SUCCESS) + return vn_error(dev->instance, result); + + result = + vn_WaitForFences(device, 1, &queue->wait_fence, VK_TRUE, UINT64_MAX); + vn_ResetFences(device, 1, &queue->wait_fence); + + return vn_result(dev->instance, result); } VkResult @@ -316,13 +385,14 @@ vn_QueueSignalReleaseImageANDROID(VkQueue queue, */ VkResult result = VK_SUCCESS; struct vn_queue *que = vn_queue_from_handle(queue); + struct vn_image *img = vn_image_from_handle(image); const VkAllocationCallbacks *alloc = &que->device->base.base.alloc; VkDevice device = vn_device_to_handle(que->device); VkPipelineStageFlags local_stage_masks[8]; VkPipelineStageFlags *stage_masks = local_stage_masks; - if (waitSemaphoreCount == 0) - goto out; + if (!vn_is_queue_compatible_with_wsi(que)) + return vn_error(que->device->instance, VK_ERROR_UNKNOWN); if (waitSemaphoreCount > ARRAY_SIZE(local_stage_masks)) { stage_masks = @@ -343,12 +413,15 @@ vn_QueueSignalReleaseImageANDROID(VkQueue queue, .waitSemaphoreCount = waitSemaphoreCount, .pWaitSemaphores = pWaitSemaphores, .pWaitDstStageMask = stage_masks, - .commandBufferCount = 0, - .pCommandBuffers = NULL, + .commandBufferCount = 1, + .pCommandBuffers = + &img->ownership_cmds[que->family].cmds[VN_IMAGE_OWNERSHIP_RELEASE], .signalSemaphoreCount = 0, .pSignalSemaphores = NULL, }; result = vn_QueueSubmit(queue, 1, &submit_info, que->wait_fence); + if (stage_masks != local_stage_masks) + vk_free(alloc, stage_masks); if (result != VK_SUCCESS) goto out; @@ -356,7 +429,99 @@ vn_QueueSignalReleaseImageANDROID(VkQueue queue, vn_WaitForFences(device, 1, &que->wait_fence, VK_TRUE, UINT64_MAX); vn_ResetFences(device, 1, &que->wait_fence); + img->acquire_queue = que; + out: *pNativeFenceFd = -1; return result; } + +VkResult +vn_android_wsi_init(struct vn_device *dev, const VkAllocationCallbacks *alloc) +{ + VkResult result = VK_SUCCESS; + + struct vn_android_wsi *android_wsi = + vk_zalloc(alloc, sizeof(struct vn_android_wsi), VN_DEFAULT_ALIGN, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (!android_wsi) + return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + const uint32_t count = dev->physical_device->queue_family_count; + if (count > 1) { + android_wsi->queue_family_indices = + vk_alloc(alloc, sizeof(uint32_t) * count, VN_DEFAULT_ALIGN, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (!android_wsi->queue_family_indices) { + result = VK_ERROR_OUT_OF_HOST_MEMORY; + goto fail; + } + + for (uint32_t i = 0; i < count; i++) + android_wsi->queue_family_indices[i] = i; + } + + android_wsi->cmd_pools = + vk_zalloc(alloc, sizeof(VkCommandPool) * count, VN_DEFAULT_ALIGN, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (!android_wsi->cmd_pools) { + result = VK_ERROR_OUT_OF_HOST_MEMORY; + goto fail; + } + + VkDevice device = vn_device_to_handle(dev); + for (uint32_t i = 0; i < count; i++) { + const VkCommandPoolCreateInfo cmd_pool_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + .pNext = NULL, + .flags = 0, + .queueFamilyIndex = i, + }; + result = vn_CreateCommandPool(device, &cmd_pool_info, alloc, + &android_wsi->cmd_pools[i]); + if (result != VK_SUCCESS) + goto fail; + } + + mtx_init(&android_wsi->cmd_pools_lock, mtx_plain); + + dev->android_wsi = android_wsi; + + return VK_SUCCESS; + +fail: + if (android_wsi->cmd_pools) { + for (uint32_t i = 0; i < count; i++) { + if (android_wsi->cmd_pools[i] != VK_NULL_HANDLE) + vn_DestroyCommandPool(device, android_wsi->cmd_pools[i], alloc); + } + vk_free(alloc, android_wsi->cmd_pools); + } + + if (android_wsi->queue_family_indices) + vk_free(alloc, android_wsi->queue_family_indices); + + vk_free(alloc, android_wsi); + + return vn_error(dev->instance, result); +} + +void +vn_android_wsi_fini(struct vn_device *dev, const VkAllocationCallbacks *alloc) +{ + if (!dev->android_wsi) + return; + + mtx_destroy(&dev->android_wsi->cmd_pools_lock); + + VkDevice device = vn_device_to_handle(dev); + for (uint32_t i = 0; i < dev->physical_device->queue_family_count; i++) { + vn_DestroyCommandPool(device, dev->android_wsi->cmd_pools[i], alloc); + } + vk_free(alloc, dev->android_wsi->cmd_pools); + + if (dev->android_wsi->queue_family_indices) + vk_free(alloc, dev->android_wsi->queue_family_indices); + + vk_free(alloc, dev->android_wsi); +} diff --git a/src/virtio/vulkan/vn_android.h b/src/virtio/vulkan/vn_android.h index f18ce7f2694..0d53656214c 100644 --- a/src/virtio/vulkan/vn_android.h +++ b/src/virtio/vulkan/vn_android.h @@ -11,6 +11,8 @@ #ifndef VN_ANDROID_H #define VN_ANDROID_H +#include "vn_common.h" + #include <vulkan/vk_android_native_buffer.h> #include <vulkan/vulkan.h> @@ -20,6 +22,15 @@ struct vn_device; struct vn_image; +struct vn_android_wsi { + /* command pools, one per queue family */ + VkCommandPool *cmd_pools; + /* use one lock to simplify */ + mtx_t cmd_pools_lock; + /* for forcing VK_SHARING_MODE_CONCURRENT */ + uint32_t *queue_family_indices; +}; + VkResult vn_image_from_anb(struct vn_device *dev, const VkImageCreateInfo *image_info, @@ -27,4 +38,28 @@ vn_image_from_anb(struct vn_device *dev, const VkAllocationCallbacks *alloc, struct vn_image **out_img); +#ifdef ANDROID +VkResult +vn_android_wsi_init(struct vn_device *dev, + const VkAllocationCallbacks *alloc); + +void +vn_android_wsi_fini(struct vn_device *dev, + const VkAllocationCallbacks *alloc); +#else +static inline VkResult +vn_android_wsi_init(UNUSED struct vn_device *dev, + UNUSED const VkAllocationCallbacks *alloc) +{ + return VK_SUCCESS; +} + +static inline void +vn_android_wsi_fini(UNUSED struct vn_device *dev, + UNUSED const VkAllocationCallbacks *alloc) +{ + return; +} +#endif + #endif /* VN_ANDROID_H */ diff --git a/src/virtio/vulkan/vn_device.c b/src/virtio/vulkan/vn_device.c index 0a742d3e00c..ef7af79501e 100644 --- a/src/virtio/vulkan/vn_device.c +++ b/src/virtio/vulkan/vn_device.c @@ -3158,6 +3158,12 @@ vn_CreateDevice(VkPhysicalDevice physicalDevice, goto fail; } + if (dev->base.base.enabled_extensions.ANDROID_native_buffer) { + result = vn_android_wsi_init(dev, alloc); + if (result != VK_SUCCESS) + goto fail; + } + for (uint32_t i = 0; i < ARRAY_SIZE(dev->memory_pools); i++) { struct vn_device_memory_pool *pool = &dev->memory_pools[i]; mtx_init(&pool->mutex, mtx_plain); @@ -3188,6 +3194,9 @@ vn_DestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) if (!dev) return; + if (dev->base.base.enabled_extensions.ANDROID_native_buffer) + vn_android_wsi_fini(dev, alloc); + for (uint32_t i = 0; i < ARRAY_SIZE(dev->memory_pools); i++) vn_device_memory_pool_fini(dev, i); diff --git a/src/virtio/vulkan/vn_device.h b/src/virtio/vulkan/vn_device.h index 554c23fb7e1..ebac430e5b2 100644 --- a/src/virtio/vulkan/vn_device.h +++ b/src/virtio/vulkan/vn_device.h @@ -112,6 +112,8 @@ struct vn_device { uint32_t queue_count; struct vn_device_memory_pool memory_pools[VK_MAX_MEMORY_TYPES]; + + struct vn_android_wsi *android_wsi; }; VK_DEFINE_HANDLE_CASTS(vn_device, base.base.base, diff --git a/src/virtio/vulkan/vn_image.c b/src/virtio/vulkan/vn_image.c index 6e86c8aaba9..c7e6bbd0b47 100644 --- a/src/virtio/vulkan/vn_image.c +++ b/src/virtio/vulkan/vn_image.c @@ -18,6 +18,154 @@ #include "vn_android.h" #include "vn_device.h" #include "vn_device_memory.h" +#include "vn_queue.h" + +static VkResult +vn_record_ownership_cmds(struct vn_device *dev, + struct vn_image *img, + uint32_t family, + uint32_t internal_index, + uint32_t external_index, + VkCommandBuffer *out_cmds) +{ + VkResult result = VK_SUCCESS; + VkDevice device = vn_device_to_handle(dev); + VkImage image = vn_image_to_handle(img); + VkCommandBuffer cmds[2]; + + const VkCommandBufferAllocateInfo cmd_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + .pNext = NULL, + .commandPool = dev->android_wsi->cmd_pools[family], + .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, + .commandBufferCount = 2, + }; + + mtx_lock(&dev->android_wsi->cmd_pools_lock); + result = vn_AllocateCommandBuffers(device, &cmd_info, cmds); + mtx_unlock(&dev->android_wsi->cmd_pools_lock); + + if (result != VK_SUCCESS) + return vn_error(dev->instance, result); + + /* record the foreign/external queue to internal queue transfer */ + const VkCommandBufferBeginInfo begin_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + }; + vn_BeginCommandBuffer(cmds[VN_IMAGE_OWNERSHIP_ACQUIRE], &begin_info); + VkImageMemoryBarrier barrier = { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = NULL, + .srcAccessMask = 0, + .dstAccessMask = 0, + .oldLayout = VK_IMAGE_LAYOUT_GENERAL, + .newLayout = VK_IMAGE_LAYOUT_GENERAL, + .srcQueueFamilyIndex = external_index, + .dstQueueFamilyIndex = internal_index, + .image = image, + .subresourceRange = + { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }; + vn_CmdPipelineBarrier( + cmds[VN_IMAGE_OWNERSHIP_ACQUIRE], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, NULL, 0, NULL, 1, &barrier); + vn_EndCommandBuffer(cmds[VN_IMAGE_OWNERSHIP_ACQUIRE]); + + /* record the internal queue to foreign/external queue transfer */ + vn_BeginCommandBuffer(cmds[VN_IMAGE_OWNERSHIP_RELEASE], &begin_info); + barrier.srcQueueFamilyIndex = internal_index; + barrier.dstQueueFamilyIndex = external_index; + vn_CmdPipelineBarrier( + cmds[VN_IMAGE_OWNERSHIP_RELEASE], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, NULL, 0, NULL, 1, &barrier); + vn_EndCommandBuffer(cmds[VN_IMAGE_OWNERSHIP_RELEASE]); + + out_cmds[VN_IMAGE_OWNERSHIP_ACQUIRE] = cmds[VN_IMAGE_OWNERSHIP_ACQUIRE]; + out_cmds[VN_IMAGE_OWNERSHIP_RELEASE] = cmds[VN_IMAGE_OWNERSHIP_RELEASE]; + + return VK_SUCCESS; +} + +VkResult +vn_image_android_wsi_init(struct vn_device *dev, + struct vn_image *img, + const VkAllocationCallbacks *alloc) +{ + VkDevice device = vn_device_to_handle(dev); + VkResult result = VK_SUCCESS; + const uint32_t internal_index = + img->sharing_mode == VK_SHARING_MODE_EXCLUSIVE + ? 0 + : VK_QUEUE_FAMILY_IGNORED; + const uint32_t external_index = + (dev->base.base.enabled_extensions.EXT_queue_family_foreign || + dev->physical_device->renderer_extensions.EXT_queue_family_foreign) + ? VK_QUEUE_FAMILY_FOREIGN_EXT + : VK_QUEUE_FAMILY_EXTERNAL; + const uint32_t count = dev->physical_device->queue_family_count; + + struct vn_image_ownership_cmds *local_cmds = + vk_zalloc(alloc, sizeof(*local_cmds) * count, VN_DEFAULT_ALIGN, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (!local_cmds) + return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + for (uint32_t i = 0; i < count; i++) { + /* skip recording if no queue is created from this family */ + uint32_t j = 0; + for (; j < dev->queue_count; j++) { + if (dev->queues[j].family == i) + break; + } + if (j == dev->queue_count) + continue; + + result = vn_record_ownership_cmds(dev, img, i, internal_index, + external_index, local_cmds[i].cmds); + if (result != VK_SUCCESS) + goto fail; + } + + img->ownership_cmds = local_cmds; + + return VK_SUCCESS; + +fail: + for (uint32_t i = 0; i < count; i++) { + if (local_cmds[i].cmds[0] != VK_NULL_HANDLE) + vn_FreeCommandBuffers(device, dev->android_wsi->cmd_pools[i], 2, + local_cmds[i].cmds); + } + vk_free(alloc, local_cmds); + return vn_error(dev->instance, result); +} + +static void +vn_image_android_wsi_fini(struct vn_device *dev, + struct vn_image *img, + const VkAllocationCallbacks *alloc) +{ + if (!dev->android_wsi || !img->ownership_cmds) + return; + + VkDevice device = vn_device_to_handle(dev); + + mtx_lock(&dev->android_wsi->cmd_pools_lock); + for (uint32_t i = 0; i < dev->physical_device->queue_family_count; i++) { + if (img->ownership_cmds[i].cmds[0] != VK_NULL_HANDLE) + vn_FreeCommandBuffers(device, dev->android_wsi->cmd_pools[i], 2, + img->ownership_cmds[i].cmds); + } + mtx_unlock(&dev->android_wsi->cmd_pools_lock); + + vk_free(alloc, img->ownership_cmds); +} static void vn_image_init_memory_requirements(struct vn_image *img, @@ -125,6 +273,8 @@ vn_image_create(struct vn_device *dev, vn_image_init_memory_requirements(img, dev, create_info); + img->sharing_mode = create_info->sharingMode; + *out_img = img; return VK_SUCCESS; @@ -186,6 +336,8 @@ vn_DestroyImage(VkDevice device, if (!img) return; + vn_image_android_wsi_fini(dev, img, alloc); + if (img->private_memory != VK_NULL_HANDLE) vn_FreeMemory(device, img->private_memory, pAllocator); diff --git a/src/virtio/vulkan/vn_image.h b/src/virtio/vulkan/vn_image.h index f134ca2640a..b8fe8d3c6b4 100644 --- a/src/virtio/vulkan/vn_image.h +++ b/src/virtio/vulkan/vn_image.h @@ -13,6 +13,15 @@ #include "vn_common.h" +enum { + VN_IMAGE_OWNERSHIP_ACQUIRE = 0, + VN_IMAGE_OWNERSHIP_RELEASE = 1, +}; + +struct vn_image_ownership_cmds { + VkCommandBuffer cmds[2]; +}; + struct vn_image { struct vn_object_base base; @@ -20,6 +29,10 @@ struct vn_image { VkMemoryDedicatedRequirements dedicated_requirements[4]; /* For VK_ANDROID_native_buffer, the WSI image owns the memory, */ VkDeviceMemory private_memory; + /* For queue family ownership transfer of WSI images */ + VkSharingMode sharing_mode; + struct vn_image_ownership_cmds *ownership_cmds; + struct vn_queue *acquire_queue; }; VK_DEFINE_NONDISP_HANDLE_CASTS(vn_image, base.base, @@ -56,4 +69,9 @@ vn_image_create(struct vn_device *dev, const VkAllocationCallbacks *alloc, struct vn_image **out_img); +VkResult +vn_image_android_wsi_init(struct vn_device *dev, + struct vn_image *img, + const VkAllocationCallbacks *alloc); + #endif /* VN_IMAGE_H */ |