venus: emulate a second graphics queue on Android

Starting from Android 14 (Android U), framework HWUI has required a
second graphics queue to avoid racing between webview and skiavk. For
non-Android, we leave the second queue emulation behind a debug option.

Signed-off-by: Yiwei Zhang <zzyiwei@chromium.org>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/30985>
This commit is contained in:
Yiwei Zhang 2024-08-27 02:01:33 -07:00 committed by Marge Bot
parent d92f9c3d51
commit d0e02df3a6
6 changed files with 66 additions and 5 deletions

View file

@ -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 */
};

View file

@ -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 {

View file

@ -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);

View file

@ -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
*/

View file

@ -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;

View file

@ -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;