vkr: move queue creation into device creation and handle errors

vkr_queue_create returns the created queue or NULL for simplicity and we
map NULL to VK_ERROR_OUT_OF_HOST_MEMORY.

Signed-off-by: Yiwei Zhang <zzyiwei@chromium.org>
Reviewed-by: Chia-I Wu <olvaffe@gmail.com>
Reviewed-by: Ryan Neph <ryanneph@google.com>
diff --git a/src/venus/vkr_device.c b/src/venus/vkr_device.c
index eadf347..57b4ca8 100644
--- a/src/venus/vkr_device.c
+++ b/src/venus/vkr_device.c
@@ -14,6 +14,44 @@
 #include "vkr_physical_device.h"
 #include "vkr_queue.h"
 
+static VkResult
+vkr_device_create_queues(struct vkr_context *ctx,
+                         struct vkr_device *dev,
+                         uint32_t create_info_count,
+                         const VkDeviceQueueCreateInfo *create_infos)
+{
+   list_inithead(&dev->queues);
+
+   for (uint32_t i = 0; i < create_info_count; i++) {
+      for (uint32_t j = 0; j < create_infos[i].queueCount; j++) {
+         const VkDeviceQueueInfo2 info = {
+            .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2,
+            .pNext = NULL,
+            .flags = create_infos[i].flags,
+            .queueFamilyIndex = create_infos[i].queueFamilyIndex,
+            .queueIndex = j,
+         };
+         VkQueue handle = VK_NULL_HANDLE;
+         vkGetDeviceQueue2(dev->base.handle.device, &info, &handle);
+
+         struct vkr_queue *queue = vkr_queue_create(
+            ctx, dev, info.flags, info.queueFamilyIndex, info.queueIndex, handle);
+         if (!queue) {
+            struct vkr_queue *entry, *tmp;
+            LIST_FOR_EACH_ENTRY_SAFE (entry, tmp, &dev->queues, base.track_head)
+               vkr_queue_destroy(ctx, entry);
+
+            return VK_ERROR_OUT_OF_HOST_MEMORY;
+         }
+
+         /* queues are not tracked as device objects */
+         list_add(&queue->base.track_head, &dev->queues);
+      }
+   }
+
+   return VK_SUCCESS;
+}
+
 static void
 vkr_device_init_entry_points(struct vkr_device *dev, uint32_t api_version)
 {
@@ -168,9 +206,15 @@
 
    dev->physical_device = physical_dev;
 
-   vkr_device_init_entry_points(dev, physical_dev->api_version);
+   args->ret = vkr_device_create_queues(ctx, dev, args->pCreateInfo->queueCreateInfoCount,
+                                        args->pCreateInfo->pQueueCreateInfos);
+   if (args->ret != VK_SUCCESS) {
+      vkDestroyDevice(dev->base.handle.device, NULL);
+      free(dev);
+      return;
+   }
 
-   list_inithead(&dev->queues);
+   vkr_device_init_entry_points(dev, physical_dev->api_version);
 
    mtx_init(&dev->free_sync_mutex, mtx_plain);
    list_inithead(&dev->free_syncs);
diff --git a/src/venus/vkr_queue.c b/src/venus/vkr_queue.c
index 576028c..734dbc4 100644
--- a/src/venus/vkr_queue.c
+++ b/src/venus/vkr_queue.c
@@ -148,7 +148,10 @@
    list_del(&queue->busy_head);
    list_del(&queue->base.track_head);
 
-   util_hash_table_remove_u64(ctx->object_table, queue->base.id);
+   if (queue->base.id)
+      util_hash_table_remove_u64(ctx->object_table, queue->base.id);
+   else
+      free(queue);
 }
 
 static int
@@ -199,29 +202,23 @@
    return 0;
 }
 
-static struct vkr_queue *
+struct vkr_queue *
 vkr_queue_create(struct vkr_context *ctx,
                  struct vkr_device *dev,
-                 vkr_object_id id,
-                 VkQueue handle,
                  VkDeviceQueueCreateFlags flags,
                  uint32_t family,
-                 uint32_t index)
+                 uint32_t index,
+                 VkQueue handle)
 {
    struct vkr_queue *queue;
    int ret;
 
-   LIST_FOR_EACH_ENTRY (queue, &dev->queues, base.track_head) {
-      if (queue->flags == flags && queue->family == family && queue->index == index)
-         return queue;
-   }
-
    queue = calloc(1, sizeof(*queue));
    if (!queue)
       return NULL;
 
    queue->base.type = VK_OBJECT_TYPE_QUEUE;
-   queue->base.id = id;
+   /* queue->base.id is not assigned until vkr_queue_assign_object_id */
    queue->base.handle.queue = handle;
 
    queue->context = ctx;
@@ -257,16 +254,44 @@
    }
 
    list_inithead(&queue->busy_head);
-
-   /* queues are not tracked as device objects */
-   list_addtail(&queue->base.track_head, &dev->queues);
-
-   util_hash_table_set_u64(ctx->object_table, queue->base.id, queue);
+   list_inithead(&queue->base.track_head);
 
    return queue;
 }
 
 static void
+vkr_queue_assign_object_id(struct vkr_context *ctx,
+                           struct vkr_queue *queue,
+                           vkr_object_id id)
+{
+   if (queue->base.id) {
+      if (queue->base.id != id)
+         vkr_cs_decoder_set_fatal(&ctx->decoder);
+      return;
+   }
+
+   queue->base.id = id;
+
+   util_hash_table_set_u64(ctx->object_table, queue->base.id, queue);
+}
+
+static struct vkr_queue *
+vkr_device_lookup_queue(struct vkr_device *dev,
+                        VkDeviceQueueCreateFlags flags,
+                        uint32_t family,
+                        uint32_t index)
+{
+   struct vkr_queue *queue;
+
+   LIST_FOR_EACH_ENTRY (queue, &dev->queues, base.track_head) {
+      if (queue->flags == flags && queue->family == family && queue->index == index)
+         return queue;
+   }
+
+   return NULL;
+}
+
+static void
 vkr_dispatch_vkGetDeviceQueue(struct vn_dispatch_context *dispatch,
                               struct vn_command_vkGetDeviceQueue *args)
 {
@@ -278,18 +303,16 @@
       return;
    }
 
+   struct vkr_queue *queue = vkr_device_lookup_queue(
+      dev, 0 /* flags */, args->queueFamilyIndex, args->queueIndex);
+   if (!queue) {
+      vkr_cs_decoder_set_fatal(&ctx->decoder);
+      return;
+   }
+
    const vkr_object_id id =
       vkr_cs_handle_load_id((const void **)args->pQueue, VK_OBJECT_TYPE_QUEUE);
-
-   VkQueue handle;
-   vn_replace_vkGetDeviceQueue_args_handle(args);
-   vkGetDeviceQueue(args->device, args->queueFamilyIndex, args->queueIndex, &handle);
-
-   struct vkr_queue *queue = vkr_queue_create(ctx, dev, id, handle, 0 /* flags */,
-                                              args->queueFamilyIndex, args->queueIndex);
-   /* TODO create queues with device and deal with failures there */
-   if (!queue)
-      vrend_printf("failed to create queue\n");
+   vkr_queue_assign_object_id(ctx, queue, id);
 }
 
 static void
@@ -304,16 +327,17 @@
       return;
    }
 
+   struct vkr_queue *queue = vkr_device_lookup_queue(dev, args->pQueueInfo->flags,
+                                                     args->pQueueInfo->queueFamilyIndex,
+                                                     args->pQueueInfo->queueIndex);
+   if (!queue) {
+      vkr_cs_decoder_set_fatal(&ctx->decoder);
+      return;
+   }
+
    const vkr_object_id id =
       vkr_cs_handle_load_id((const void **)args->pQueue, VK_OBJECT_TYPE_QUEUE);
-
-   VkQueue handle;
-   vn_replace_vkGetDeviceQueue2_args_handle(args);
-   vkGetDeviceQueue2(args->device, args->pQueueInfo, &handle);
-
-   /* TODO deal with errors */
-   vkr_queue_create(ctx, dev, id, handle, args->pQueueInfo->flags,
-                    args->pQueueInfo->queueFamilyIndex, args->pQueueInfo->queueIndex);
+   vkr_queue_assign_object_id(ctx, queue, id);
 }
 
 static void
diff --git a/src/venus/vkr_queue.h b/src/venus/vkr_queue.h
index 16e144d..8e7bdb7 100644
--- a/src/venus/vkr_queue.h
+++ b/src/venus/vkr_queue.h
@@ -91,6 +91,14 @@
                        struct list_head *retired_syncs,
                        bool *queue_empty);
 
+struct vkr_queue *
+vkr_queue_create(struct vkr_context *ctx,
+                 struct vkr_device *dev,
+                 VkDeviceQueueCreateFlags flags,
+                 uint32_t family,
+                 uint32_t index,
+                 VkQueue handle);
+
 void
 vkr_queue_destroy(struct vkr_context *ctx, struct vkr_queue *queue);