/* This file is generated by vkr_device_object.py. */

#ifndef VKR_DESCRIPTOR_SET_GEN_H
#define VKR_DESCRIPTOR_SET_GEN_H

#include "vkr_common.h"

#include "venus-protocol/vn_protocol_renderer_descriptor_set_layout.h"
#include "venus-protocol/vn_protocol_renderer_descriptor_pool.h"
#include "venus-protocol/vn_protocol_renderer_descriptor_set.h"
#include "venus-protocol/vn_protocol_renderer_descriptor_update_template.h"

#include "vkr_context.h"
#include "vkr_device.h"

/* create a driver VkDescriptorSetLayout and update the vkr_descriptor_set_layout */
static inline VkResult
vkr_descriptor_set_layout_create_driver_handle(
   UNUSED struct vkr_context *ctx,
   struct vn_command_vkCreateDescriptorSetLayout *args,
   struct vkr_descriptor_set_layout *obj)
{
   struct vkr_device *dev = vkr_device_from_handle(args->device);
   struct vn_device_proc_table *vk = &dev->proc_table;

   /* handles in args are replaced */
   vn_replace_vkCreateDescriptorSetLayout_args_handle(args);
   args->ret = vk->CreateDescriptorSetLayout(args->device, args->pCreateInfo, NULL,
      &obj->base.handle.descriptor_set_layout);
   return args->ret;
}

/* create a vkr_descriptor_set_layout */
static inline struct vkr_descriptor_set_layout *
vkr_descriptor_set_layout_create(
   struct vkr_context *ctx,
   struct vn_command_vkCreateDescriptorSetLayout *args)
{
   struct vkr_descriptor_set_layout *obj = vkr_context_alloc_object(ctx, sizeof(*obj),
      VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, args->pSetLayout);
   if (!obj) {
      args->ret = VK_ERROR_OUT_OF_HOST_MEMORY;
      return NULL;
   }

   /* handles in args are replaced */
   if (vkr_descriptor_set_layout_create_driver_handle(ctx, args, obj) != VK_SUCCESS) {
      free(obj);
      return NULL;
   }

   return obj;
}

/* create a vkr_descriptor_set_layout and add it to the vkr_device */
static inline struct vkr_descriptor_set_layout *
vkr_descriptor_set_layout_create_and_add(
   struct vkr_context *ctx,
   struct vn_command_vkCreateDescriptorSetLayout *args)
{
   struct vkr_device *dev = vkr_device_from_handle(args->device);

   struct vkr_descriptor_set_layout *obj = vkr_descriptor_set_layout_create(ctx, args);
   if (!obj)
      return NULL;

   vkr_device_add_object(ctx, dev, &obj->base);
   return obj;
}

/* destroy a driver VkDescriptorSetLayout */
static inline void
vkr_descriptor_set_layout_destroy_driver_handle(
   UNUSED struct vkr_context *ctx,
   struct vn_command_vkDestroyDescriptorSetLayout *args)
{
   struct vkr_device *dev = vkr_device_from_handle(args->device);
   struct vn_device_proc_table *vk = &dev->proc_table;

   /* handles in args are replaced */
   vn_replace_vkDestroyDescriptorSetLayout_args_handle(args);
   vk->DestroyDescriptorSetLayout(args->device, args->descriptorSetLayout, NULL);
}

/* remove a vkr_descriptor_set_layout from the device and destroy it */
static inline void
vkr_descriptor_set_layout_destroy_and_remove(
   struct vkr_context *ctx,
   struct vn_command_vkDestroyDescriptorSetLayout *args)
{
   struct vkr_device *dev = vkr_device_from_handle(args->device);
   struct vkr_descriptor_set_layout *obj = vkr_descriptor_set_layout_from_handle(args->descriptorSetLayout);
   if (!obj)
      return;

   vkr_descriptor_set_layout_destroy_driver_handle(ctx, args);

   vkr_device_remove_object(ctx, dev, &obj->base);
}

/* create a driver VkDescriptorPool and update the vkr_descriptor_pool */
static inline VkResult
vkr_descriptor_pool_create_driver_handle(
   UNUSED struct vkr_context *ctx,
   struct vn_command_vkCreateDescriptorPool *args,
   struct vkr_descriptor_pool *obj)
{
   struct vkr_device *dev = vkr_device_from_handle(args->device);
   struct vn_device_proc_table *vk = &dev->proc_table;

   /* handles in args are replaced */
   vn_replace_vkCreateDescriptorPool_args_handle(args);
   args->ret = vk->CreateDescriptorPool(args->device, args->pCreateInfo, NULL,
      &obj->base.handle.descriptor_pool);
   return args->ret;
}

/* create a vkr_descriptor_pool */
static inline struct vkr_descriptor_pool *
vkr_descriptor_pool_create(
   struct vkr_context *ctx,
   struct vn_command_vkCreateDescriptorPool *args)
{
   struct vkr_descriptor_pool *obj = vkr_context_alloc_object(ctx, sizeof(*obj),
      VK_OBJECT_TYPE_DESCRIPTOR_POOL, args->pDescriptorPool);
   if (!obj) {
      args->ret = VK_ERROR_OUT_OF_HOST_MEMORY;
      return NULL;
   }

   /* handles in args are replaced */
   if (vkr_descriptor_pool_create_driver_handle(ctx, args, obj) != VK_SUCCESS) {
      free(obj);
      return NULL;
   }

   return obj;
}

/* create a vkr_descriptor_pool and add it to the vkr_device */
static inline struct vkr_descriptor_pool *
vkr_descriptor_pool_create_and_add(
   struct vkr_context *ctx,
   struct vn_command_vkCreateDescriptorPool *args)
{
   struct vkr_device *dev = vkr_device_from_handle(args->device);

   struct vkr_descriptor_pool *obj = vkr_descriptor_pool_create(ctx, args);
   if (!obj)
      return NULL;

   vkr_device_add_object(ctx, dev, &obj->base);
   return obj;
}

/* destroy a driver VkDescriptorPool */
static inline void
vkr_descriptor_pool_destroy_driver_handle(
   UNUSED struct vkr_context *ctx,
   struct vn_command_vkDestroyDescriptorPool *args)
{
   struct vkr_device *dev = vkr_device_from_handle(args->device);
   struct vn_device_proc_table *vk = &dev->proc_table;

   /* handles in args are replaced */
   vn_replace_vkDestroyDescriptorPool_args_handle(args);
   vk->DestroyDescriptorPool(args->device, args->descriptorPool, NULL);
}

/* remove a vkr_descriptor_pool from the device and destroy it */
static inline void
vkr_descriptor_pool_destroy_and_remove(
   struct vkr_context *ctx,
   struct vn_command_vkDestroyDescriptorPool *args)
{
   struct vkr_device *dev = vkr_device_from_handle(args->device);
   struct vkr_descriptor_pool *obj = vkr_descriptor_pool_from_handle(args->descriptorPool);
   if (!obj)
      return;

   vkr_descriptor_pool_destroy_driver_handle(ctx, args);

   vkr_device_remove_object(ctx, dev, &obj->base);
}

/* initialize an object_array for vkr_descriptor_sets */
static inline VkResult
vkr_descriptor_set_init_array(
   struct vkr_context *ctx,
   struct vn_command_vkAllocateDescriptorSets *args,
   struct object_array *arr)
{
   args->ret = object_array_init(ctx, arr, args->pAllocateInfo->descriptorSetCount,
                                 VK_OBJECT_TYPE_DESCRIPTOR_SET, sizeof(struct vkr_descriptor_set),
                                 sizeof(*args->pDescriptorSets),
                                 args->pDescriptorSets)
                  ? VK_SUCCESS
                  : VK_ERROR_OUT_OF_HOST_MEMORY;
   return args->ret;
}

/* create an array of driver VkDescriptorSets from a pool and update the
 * object_array
 */
static inline
VkResult vkr_descriptor_set_create_driver_handles(
   UNUSED struct vkr_context *ctx,
   struct vn_command_vkAllocateDescriptorSets *args,
   struct object_array *arr)
{
   struct vkr_device *dev = vkr_device_from_handle(args->device);
   struct vn_device_proc_table *vk = &dev->proc_table;

   /* handles in args are replaced */
   vn_replace_vkAllocateDescriptorSets_args_handle(args);
   args->ret = vk->AllocateDescriptorSets(args->device, args->pAllocateInfo,
      arr->handle_storage);
   return args->ret;
}

/* create an array of vkr_descriptor_sets */
static inline VkResult
vkr_descriptor_set_create_array(
   struct vkr_context *ctx,
   struct vn_command_vkAllocateDescriptorSets *args,
   struct object_array *arr)
{
   if (vkr_descriptor_set_init_array(ctx, args, arr) != VK_SUCCESS)
      return args->ret;

   if (vkr_descriptor_set_create_driver_handles(ctx, args, arr) < VK_SUCCESS) {
      /* In case the client expects a reply, clear all returned handles to
       * VK_NULL_HANDLE.
       */
      memset(args->pDescriptorSets, 0,
             args->pAllocateInfo->descriptorSetCount * sizeof(args->pDescriptorSets[0]));
      object_array_fini(arr);
      return args->ret;
   }

   return args->ret;
}

/* steal vkr_descriptor_sets from an object_array and add them to the
 * vkr_descriptor_pool and the context
 */
static inline
void vkr_descriptor_set_add_array(
   struct vkr_context *ctx,
   struct vkr_device *dev,
   struct vkr_descriptor_pool *pool,
   struct object_array *arr)
{
   for (uint32_t i = 0; i < arr->count; i++) {
      struct vkr_descriptor_set *obj = arr->objects[i];

      obj->base.handle.descriptor_set = ((VkDescriptorSet *)arr->handle_storage)[i];
      obj->device = dev;

      /* pool objects are tracked by the pool other than the device */
      list_add(&obj->base.track_head, &pool->descriptor_sets);

      vkr_context_add_object(ctx, &obj->base);
   }

   arr->objects_stolen = true;
   object_array_fini(arr);
}

/* destroy an array of driver VkDescriptorSets from a pool, remove them from the
 * vkr_descriptor_pool, and return the list of affected vkr_descriptor_sets
 */
static inline void
vkr_descriptor_set_destroy_driver_handles(
   UNUSED struct vkr_context *ctx,
   struct vn_command_vkFreeDescriptorSets *args,
   struct list_head *free_list)
{
   struct vkr_device *dev = vkr_device_from_handle(args->device);
   struct vn_device_proc_table *vk = &dev->proc_table;

   list_inithead(free_list);
   for (uint32_t i = 0; i < args->descriptorSetCount; i++) {
      struct vkr_descriptor_set *obj =
         vkr_descriptor_set_from_handle(args->pDescriptorSets[i]);
      if (!obj)
         continue;

      list_del(&obj->base.track_head);
      list_addtail(&obj->base.track_head, free_list);
   }

   /* handles in args are replaced */
   vn_replace_vkFreeDescriptorSets_args_handle(args);
   vk->FreeDescriptorSets(args->device, args->descriptorPool,
      args->descriptorSetCount, args->pDescriptorSets);
}

/* create a driver VkDescriptorUpdateTemplate and update the vkr_descriptor_update_template */
static inline VkResult
vkr_descriptor_update_template_create_driver_handle(
   UNUSED struct vkr_context *ctx,
   struct vn_command_vkCreateDescriptorUpdateTemplate *args,
   struct vkr_descriptor_update_template *obj)
{
   struct vkr_device *dev = vkr_device_from_handle(args->device);
   struct vn_device_proc_table *vk = &dev->proc_table;

   /* handles in args are replaced */
   vn_replace_vkCreateDescriptorUpdateTemplate_args_handle(args);
   args->ret = vk->CreateDescriptorUpdateTemplate(args->device, args->pCreateInfo, NULL,
      &obj->base.handle.descriptor_update_template);
   return args->ret;
}

/* create a vkr_descriptor_update_template */
static inline struct vkr_descriptor_update_template *
vkr_descriptor_update_template_create(
   struct vkr_context *ctx,
   struct vn_command_vkCreateDescriptorUpdateTemplate *args)
{
   struct vkr_descriptor_update_template *obj = vkr_context_alloc_object(ctx, sizeof(*obj),
      VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE, args->pDescriptorUpdateTemplate);
   if (!obj) {
      args->ret = VK_ERROR_OUT_OF_HOST_MEMORY;
      return NULL;
   }

   /* handles in args are replaced */
   if (vkr_descriptor_update_template_create_driver_handle(ctx, args, obj) != VK_SUCCESS) {
      free(obj);
      return NULL;
   }

   return obj;
}

/* create a vkr_descriptor_update_template and add it to the vkr_device */
static inline struct vkr_descriptor_update_template *
vkr_descriptor_update_template_create_and_add(
   struct vkr_context *ctx,
   struct vn_command_vkCreateDescriptorUpdateTemplate *args)
{
   struct vkr_device *dev = vkr_device_from_handle(args->device);

   struct vkr_descriptor_update_template *obj = vkr_descriptor_update_template_create(ctx, args);
   if (!obj)
      return NULL;

   vkr_device_add_object(ctx, dev, &obj->base);
   return obj;
}

/* destroy a driver VkDescriptorUpdateTemplate */
static inline void
vkr_descriptor_update_template_destroy_driver_handle(
   UNUSED struct vkr_context *ctx,
   struct vn_command_vkDestroyDescriptorUpdateTemplate *args)
{
   struct vkr_device *dev = vkr_device_from_handle(args->device);
   struct vn_device_proc_table *vk = &dev->proc_table;

   /* handles in args are replaced */
   vn_replace_vkDestroyDescriptorUpdateTemplate_args_handle(args);
   vk->DestroyDescriptorUpdateTemplate(args->device, args->descriptorUpdateTemplate, NULL);
}

/* remove a vkr_descriptor_update_template from the device and destroy it */
static inline void
vkr_descriptor_update_template_destroy_and_remove(
   struct vkr_context *ctx,
   struct vn_command_vkDestroyDescriptorUpdateTemplate *args)
{
   struct vkr_device *dev = vkr_device_from_handle(args->device);
   struct vkr_descriptor_update_template *obj = vkr_descriptor_update_template_from_handle(args->descriptorUpdateTemplate);
   if (!obj)
      return;

   vkr_descriptor_update_template_destroy_driver_handle(ctx, args);

   vkr_device_remove_object(ctx, dev, &obj->base);
}

#endif /* VKR_DESCRIPTOR_SET_GEN_H */
