diff --git a/src/virtio/vulkan/vn_common.c b/src/virtio/vulkan/vn_common.c index 7b7a1f16f35..ad73b8f4e3f 100644 --- a/src/virtio/vulkan/vn_common.c +++ b/src/virtio/vulkan/vn_common.c @@ -32,6 +32,7 @@ static const struct debug_control vn_debug_options[] = { { "cache", VN_DEBUG_CACHE }, { "no_sparse", VN_DEBUG_NO_SPARSE }, { "no_gpl", VN_DEBUG_NO_GPL }, + { "second_queue", VN_DEBUG_SECOND_QUEUE }, { NULL, 0 }, /* clang-format on */ }; diff --git a/src/virtio/vulkan/vn_common.h b/src/virtio/vulkan/vn_common.h index 21cd82d4a7f..1c75d8ec3e4 100644 --- a/src/virtio/vulkan/vn_common.h +++ b/src/virtio/vulkan/vn_common.h @@ -112,6 +112,7 @@ enum vn_debug { VN_DEBUG_CACHE = 1ull << 6, VN_DEBUG_NO_SPARSE = 1ull << 7, VN_DEBUG_NO_GPL = 1ull << 8, + VN_DEBUG_SECOND_QUEUE = 1ull << 9, }; enum vn_perf { diff --git a/src/virtio/vulkan/vn_device.c b/src/virtio/vulkan/vn_device.c index 40a2a3a0d72..054610c58f7 100644 --- a/src/virtio/vulkan/vn_device.c +++ b/src/virtio/vulkan/vn_device.c @@ -40,7 +40,8 @@ static VkResult vn_queue_init(struct vn_device *dev, struct vn_queue *queue, const VkDeviceQueueCreateInfo *queue_info, - uint32_t queue_index) + uint32_t queue_index, + struct vn_queue *shared_queue) { VkResult result = vn_queue_base_init(&queue->base, &dev->base, queue_info, queue_index); @@ -49,6 +50,16 @@ vn_queue_init(struct vn_device *dev, vn_cached_storage_init(&queue->storage, &dev->base.base.alloc); + if (dev->physical_device->emulate_second_queue == + queue_info->queueFamilyIndex && + shared_queue != NULL) { + assert(queue_index > 0); + queue->emulated = true; + queue->base.id = shared_queue->base.id; + queue->ring_idx = shared_queue->ring_idx; + return VK_SUCCESS; + } + const int ring_idx = vn_instance_acquire_ring_idx(dev->instance); if (ring_idx < 0) { vn_log(dev->instance, "failed binding VkQueue to renderer timeline"); @@ -92,13 +103,15 @@ vn_device_init_queues(struct vn_device *dev, return VK_ERROR_OUT_OF_HOST_MEMORY; count = 0; + struct vn_queue *shared_queue = NULL; for (uint32_t i = 0; i < create_info->queueCreateInfoCount; i++) { VkResult result; const VkDeviceQueueCreateInfo *queue_info = &create_info->pQueueCreateInfos[i]; for (uint32_t j = 0; j < queue_info->queueCount; j++) { - result = vn_queue_init(dev, &queues[count], queue_info, j); + result = + vn_queue_init(dev, &queues[count], queue_info, j, shared_queue); if (result != VK_SUCCESS) { for (uint32_t k = 0; k < count; k++) vn_queue_fini(&queues[k]); @@ -107,7 +120,7 @@ vn_device_init_queues(struct vn_device *dev, return result; } - count++; + shared_queue = &queues[count++]; } } @@ -470,8 +483,25 @@ vn_device_init(struct vn_device *dev, if (group && group->physicalDeviceCount) dev->device_mask = (1 << group->physicalDeviceCount) - 1; + VkDeviceCreateInfo final_create_info = *create_info; + STACK_ARRAY(VkDeviceQueueCreateInfo, queue_infos, + create_info->queueCreateInfoCount); + for (uint32_t i = 0; i < create_info->queueCreateInfoCount; i++) { + const VkDeviceQueueCreateInfo *queue_info = + &create_info->pQueueCreateInfos[i]; + if (queue_info->queueFamilyIndex == + physical_dev->emulate_second_queue && + queue_info->queueCount == 2) { + typed_memcpy(queue_infos, create_info->pQueueCreateInfos, + create_info->queueCreateInfoCount); + final_create_info.pQueueCreateInfos = queue_infos; + queue_infos[i].queueCount = 1; + break; + } + } result = vn_call_vkCreateDevice(dev->primary_ring, physical_dev_handle, - create_info, NULL, &dev_handle); + &final_create_info, NULL, &dev_handle); + STACK_ARRAY_FINISH(queue_infos); /* free the fixed extensions here since no longer needed below */ if (create_info == &local_create_info) @@ -612,7 +642,8 @@ vn_DestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) * are still bound to the queues in the renderer. */ for (uint32_t i = 0; i < dev->queue_count; i++) { - vn_instance_release_ring_idx(dev->instance, dev->queues[i].ring_idx); + if (!dev->queues[i].emulated) + vn_instance_release_ring_idx(dev->instance, dev->queues[i].ring_idx); } vk_free(alloc, dev->queues); diff --git a/src/virtio/vulkan/vn_physical_device.c b/src/virtio/vulkan/vn_physical_device.c index d3bba1143cd..3f4de6f23cb 100644 --- a/src/virtio/vulkan/vn_physical_device.c +++ b/src/virtio/vulkan/vn_physical_device.c @@ -678,6 +678,27 @@ vn_physical_device_init_queue_family_properties( vn_call_vkGetPhysicalDeviceQueueFamilyProperties2( ring, vn_physical_device_to_handle(physical_dev), &count, props); +#if DETECT_OS_ANDROID && ANDROID_API_LEVEL >= 34 + /* Starting from Android 14 (Android U), framework HWUI has required a + * second graphics queue to avoid racing between webview and skiavk. + */ + static const bool require_second_queue = true; +#else + const bool require_second_queue = VN_DEBUG(SECOND_QUEUE); +#endif + physical_dev->emulate_second_queue = -1; + for (uint32_t i = 0; i < count; i++) { + if (props[i].queueFamilyProperties.queueFlags & VK_QUEUE_GRAPHICS_BIT) { + if (require_second_queue && + props[i].queueFamilyProperties.queueCount < 2) { + props[i].queueFamilyProperties.queueCount = 2; + physical_dev->emulate_second_queue = i; + } + + break; + } + } + /* Filter out queue families that exclusively support sparse binding as * we need additional support for submitting feedback commands */ diff --git a/src/virtio/vulkan/vn_physical_device.h b/src/virtio/vulkan/vn_physical_device.h index 102d24d125c..91a50aba903 100644 --- a/src/virtio/vulkan/vn_physical_device.h +++ b/src/virtio/vulkan/vn_physical_device.h @@ -83,6 +83,10 @@ struct vn_physical_device { VkQueueFamilyProperties2 *queue_family_properties; uint32_t queue_family_count; bool sparse_binding_disabled; + /* Track the queue family index to emulate a second queue. -1 means no + * emulation is needed. + */ + int emulate_second_queue; VkPhysicalDeviceMemoryProperties memory_properties; diff --git a/src/virtio/vulkan/vn_queue.h b/src/virtio/vulkan/vn_queue.h index f1570609f81..1d46a762505 100644 --- a/src/virtio/vulkan/vn_queue.h +++ b/src/virtio/vulkan/vn_queue.h @@ -16,6 +16,9 @@ struct vn_queue { struct vn_queue_base base; + /* emulated queue shares base queue id and ring_idx with another queue */ + bool emulated; + /* only used if renderer supports multiple timelines */ uint32_t ring_idx;