Edit

IABSD.fr/xenocara/lib/mesa/src/vulkan/runtime/vk_cmd_enqueue.c

Branch :

  • Show log

    Commit

  • Author : jsg
    Date : 2025-06-05 11:23:11
    Hash : 67d6f117
    Message : Import Mesa 25.0.7

  • lib/mesa/src/vulkan/runtime/vk_cmd_enqueue.c
  • /*
     * Copyright © 2019 Red Hat.
     * Copyright © 2022 Collabora, LTD
     *
     * Permission is hereby granted, free of charge, to any person obtaining a
     * copy of this software and associated documentation files (the "Software"),
     * to deal in the Software without restriction, including without limitation
     * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     * and/or sell copies of the Software, and to permit persons to whom the
     * Software is furnished to do so, subject to the following conditions:
     *
     * The above copyright notice and this permission notice (including the next
     * paragraph) shall be included in all copies or substantial portions of the
     * Software.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     * IN THE SOFTWARE.
     */
    
    #include "vk_alloc.h"
    #include "vk_cmd_enqueue_entrypoints.h"
    #include "vk_command_buffer.h"
    #include "vk_descriptor_update_template.h"
    #include "vk_device.h"
    #include "vk_pipeline_layout.h"
    #include "vk_util.h"
    
    static inline unsigned
    vk_descriptor_type_update_size(VkDescriptorType type)
    {
       switch (type) {
       case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK:
          unreachable("handled in caller");
    
       case VK_DESCRIPTOR_TYPE_SAMPLER:
       case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
       case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
       case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
       case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
          return sizeof(VkDescriptorImageInfo);
    
       case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
       case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
          return sizeof(VkBufferView);
    
       case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
          return sizeof(VkAccelerationStructureKHR);
    
       case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
       case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
       case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
       case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
       default:
          return sizeof(VkDescriptorBufferInfo);
       }
    }
    
    static void
    vk_cmd_push_descriptor_set_with_template2_free(
       struct vk_cmd_queue *queue, struct vk_cmd_queue_entry *cmd)
    {
       struct vk_command_buffer *cmd_buffer =
          container_of(queue, struct vk_command_buffer, cmd_queue);
       struct vk_device *device = cmd_buffer->base.device;
    
       struct vk_cmd_push_descriptor_set_with_template2 *info_ =
          &cmd->u.push_descriptor_set_with_template2;
    
       VkPushDescriptorSetWithTemplateInfoKHR *info =
          info_->push_descriptor_set_with_template_info;
    
       VK_FROM_HANDLE(vk_descriptor_update_template, templ,
                      info->descriptorUpdateTemplate);
       VK_FROM_HANDLE(vk_pipeline_layout, layout, info->layout);
    
       vk_descriptor_update_template_unref(device, templ);
       vk_pipeline_layout_unref(device, layout);
    
       if (info->pNext) {
          VkPipelineLayoutCreateInfo *pnext = (void *)info->pNext;
    
          vk_free(queue->alloc, (void *)pnext->pSetLayouts);
          vk_free(queue->alloc, (void *)pnext->pPushConstantRanges);
          vk_free(queue->alloc, pnext);
       }
    }
    
    VKAPI_ATTR void VKAPI_CALL
    vk_cmd_enqueue_CmdPushDescriptorSetWithTemplate2(
       VkCommandBuffer commandBuffer,
       const VkPushDescriptorSetWithTemplateInfoKHR *pPushDescriptorSetWithTemplateInfo)
    {
       VK_FROM_HANDLE(vk_command_buffer, cmd_buffer, commandBuffer);
    
       struct vk_cmd_queue *queue = &cmd_buffer->cmd_queue;
    
       struct vk_cmd_queue_entry *cmd =
          vk_zalloc(cmd_buffer->cmd_queue.alloc, sizeof(*cmd), 8,
                    VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
       if (!cmd)
          return;
    
       cmd->type = VK_CMD_PUSH_DESCRIPTOR_SET_WITH_TEMPLATE2;
       cmd->driver_free_cb = vk_cmd_push_descriptor_set_with_template2_free;
       list_addtail(&cmd->cmd_link, &cmd_buffer->cmd_queue.cmds);
    
       VkPushDescriptorSetWithTemplateInfoKHR *info =
          vk_zalloc(cmd_buffer->cmd_queue.alloc,
                    sizeof(VkPushDescriptorSetWithTemplateInfoKHR), 8,
                    VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
    
       cmd->u.push_descriptor_set_with_template2
          .push_descriptor_set_with_template_info = info;
    
       /* From the application's perspective, the vk_cmd_queue_entry can outlive the
        * template. Therefore, we take a reference here and free it when the
        * vk_cmd_queue_entry is freed, tying the lifetimes.
        */
       info->descriptorUpdateTemplate =
          pPushDescriptorSetWithTemplateInfo->descriptorUpdateTemplate;
    
       VK_FROM_HANDLE(vk_descriptor_update_template, templ,
                      info->descriptorUpdateTemplate);
       vk_descriptor_update_template_ref(templ);
    
       info->set = pPushDescriptorSetWithTemplateInfo->set;
       info->sType = pPushDescriptorSetWithTemplateInfo->sType;
    
       /* Similar concerns for the pipeline layout */
       info->layout = pPushDescriptorSetWithTemplateInfo->layout;
    
       VK_FROM_HANDLE(vk_pipeline_layout, layout, info->layout);
       vk_pipeline_layout_ref(layout);
    
       /* What makes this tricky is that the size of pData is implicit. We determine
        * it by walking the template and determining the ranges read by the driver.
        */
       size_t data_size = 0;
       for (unsigned i = 0; i < templ->entry_count; ++i) {
          struct vk_descriptor_template_entry entry = templ->entries[i];
          unsigned end = 0;
    
          /* From the spec:
           *
           *    If descriptorType is VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK then
           *    the value of stride is ignored and the stride is assumed to be 1,
           *    i.e. the descriptor update information for them is always specified
           *    as a contiguous range.
           */
          if (entry.type == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK) {
             end = entry.offset + entry.array_count;
          } else if (entry.array_count > 0) {
             end = entry.offset + ((entry.array_count - 1) * entry.stride) +
                   vk_descriptor_type_update_size(entry.type);
          }
    
          data_size = MAX2(data_size, end);
       }
    
       uint8_t *out_pData = vk_zalloc(cmd_buffer->cmd_queue.alloc, data_size, 8,
                                      VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
       const uint8_t *pData = pPushDescriptorSetWithTemplateInfo->pData;
    
       /* Now walk the template again, copying what we actually need */
       for (unsigned i = 0; i < templ->entry_count; ++i) {
          struct vk_descriptor_template_entry entry = templ->entries[i];
          unsigned size = 0;
    
          if (entry.type == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK) {
             size = entry.array_count;
          } else if (entry.array_count > 0) {
             size = ((entry.array_count - 1) * entry.stride) +
                    vk_descriptor_type_update_size(entry.type);
          }
    
          memcpy(out_pData + entry.offset, pData + entry.offset, size);
       }
    
       info->pData = out_pData;
    
       const VkBaseInStructure *pnext = pPushDescriptorSetWithTemplateInfo->pNext;
    
       if (pnext) {
          switch ((int32_t)pnext->sType) {
          /* TODO: The set layouts below would need to be reference counted. Punting
           * until there's a cmd_enqueue-based driver implementing
           * VK_NV_per_stage_descriptor_set.
           */
    #if 0
          case VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO:
             info->pNext =
                vk_zalloc(queue->alloc, sizeof(VkPipelineLayoutCreateInfo), 8,
                          VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
             if (info->pNext == NULL)
                goto err;
    
             memcpy((void *)info->pNext, pnext,
                    sizeof(VkPipelineLayoutCreateInfo));
    
             VkPipelineLayoutCreateInfo *tmp_dst2 = (void *)info->pNext;
             VkPipelineLayoutCreateInfo *tmp_src2 = (void *)pnext;
    
             if (tmp_src2->pSetLayouts) {
                tmp_dst2->pSetLayouts = vk_zalloc(
                   queue->alloc,
                   sizeof(*tmp_dst2->pSetLayouts) * tmp_dst2->setLayoutCount, 8,
                   VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
                if (tmp_dst2->pSetLayouts == NULL)
                   goto err;
    
                memcpy(
                   (void *)tmp_dst2->pSetLayouts, tmp_src2->pSetLayouts,
                   sizeof(*tmp_dst2->pSetLayouts) * tmp_dst2->setLayoutCount);
             }
    
             if (tmp_src2->pPushConstantRanges) {
                tmp_dst2->pPushConstantRanges =
                   vk_zalloc(queue->alloc,
                             sizeof(*tmp_dst2->pPushConstantRanges) *
                                tmp_dst2->pushConstantRangeCount,
                             8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
                if (tmp_dst2->pPushConstantRanges == NULL)
                   goto err;
    
                memcpy((void *)tmp_dst2->pPushConstantRanges,
                       tmp_src2->pPushConstantRanges,
                       sizeof(*tmp_dst2->pPushConstantRanges) *
                          tmp_dst2->pushConstantRangeCount);
             }
             break;
    #endif
    
          default:
             goto err;
          }
       }
    
       return;
    
    err:
       if (cmd)
          vk_cmd_push_descriptor_set_with_template2_free(queue, cmd);
    
       vk_command_buffer_set_error(cmd_buffer, VK_ERROR_OUT_OF_HOST_MEMORY);
    }
    
    VKAPI_ATTR void VKAPI_CALL
    vk_cmd_enqueue_CmdPushDescriptorSetWithTemplate(
        VkCommandBuffer                             commandBuffer,
        VkDescriptorUpdateTemplate                  descriptorUpdateTemplate,
        VkPipelineLayout                            layout,
        uint32_t                                    set,
        const void*                                 pData)
    {
       const VkPushDescriptorSetWithTemplateInfoKHR two = {
          .sType = VK_STRUCTURE_TYPE_PUSH_DESCRIPTOR_SET_WITH_TEMPLATE_INFO_KHR,
          .descriptorUpdateTemplate = descriptorUpdateTemplate,
          .layout = layout,
          .set = set,
          .pData = pData,
       };
    
       vk_cmd_enqueue_CmdPushDescriptorSetWithTemplate2(commandBuffer, &two);
    }
    
    VKAPI_ATTR void VKAPI_CALL
    vk_cmd_enqueue_CmdDrawMultiEXT(VkCommandBuffer commandBuffer,
                                   uint32_t drawCount,
                                   const VkMultiDrawInfoEXT *pVertexInfo,
                                   uint32_t instanceCount,
                                   uint32_t firstInstance,
                                   uint32_t stride)
    {
       VK_FROM_HANDLE(vk_command_buffer, cmd_buffer, commandBuffer);
    
       struct vk_cmd_queue_entry *cmd =
          vk_zalloc(cmd_buffer->cmd_queue.alloc, sizeof(*cmd), 8,
                    VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
       if (!cmd)
          return;
    
       cmd->type = VK_CMD_DRAW_MULTI_EXT;
       list_addtail(&cmd->cmd_link, &cmd_buffer->cmd_queue.cmds);
    
       cmd->u.draw_multi_ext.draw_count = drawCount;
       if (pVertexInfo) {
          unsigned i = 0;
          cmd->u.draw_multi_ext.vertex_info =
             vk_zalloc(cmd_buffer->cmd_queue.alloc,
                       sizeof(*cmd->u.draw_multi_ext.vertex_info) * drawCount, 8,
                       VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
    
          vk_foreach_multi_draw(draw, i, pVertexInfo, drawCount, stride) {
             memcpy(&cmd->u.draw_multi_ext.vertex_info[i], draw,
                    sizeof(*cmd->u.draw_multi_ext.vertex_info));
          }
       }
       cmd->u.draw_multi_ext.instance_count = instanceCount;
       cmd->u.draw_multi_ext.first_instance = firstInstance;
       cmd->u.draw_multi_ext.stride = stride;
    }
    
    VKAPI_ATTR void VKAPI_CALL
    vk_cmd_enqueue_CmdDrawMultiIndexedEXT(VkCommandBuffer commandBuffer,
                                          uint32_t drawCount,
                                          const VkMultiDrawIndexedInfoEXT *pIndexInfo,
                                          uint32_t instanceCount,
                                          uint32_t firstInstance,
                                          uint32_t stride,
                                          const int32_t *pVertexOffset)
    {
       VK_FROM_HANDLE(vk_command_buffer, cmd_buffer, commandBuffer);
    
       struct vk_cmd_queue_entry *cmd =
          vk_zalloc(cmd_buffer->cmd_queue.alloc, sizeof(*cmd), 8,
                    VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
       if (!cmd)
          return;
    
       cmd->type = VK_CMD_DRAW_MULTI_INDEXED_EXT;
       list_addtail(&cmd->cmd_link, &cmd_buffer->cmd_queue.cmds);
    
       cmd->u.draw_multi_indexed_ext.draw_count = drawCount;
    
       if (pIndexInfo) {
          unsigned i = 0;
          cmd->u.draw_multi_indexed_ext.index_info =
             vk_zalloc(cmd_buffer->cmd_queue.alloc,
                       sizeof(*cmd->u.draw_multi_indexed_ext.index_info) * drawCount, 8,
                       VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
    
          vk_foreach_multi_draw_indexed(draw, i, pIndexInfo, drawCount, stride) {
             cmd->u.draw_multi_indexed_ext.index_info[i].firstIndex = draw->firstIndex;
             cmd->u.draw_multi_indexed_ext.index_info[i].indexCount = draw->indexCount;
             if (pVertexOffset == NULL)
                cmd->u.draw_multi_indexed_ext.index_info[i].vertexOffset = draw->vertexOffset;
          }
       }
    
       cmd->u.draw_multi_indexed_ext.instance_count = instanceCount;
       cmd->u.draw_multi_indexed_ext.first_instance = firstInstance;
       cmd->u.draw_multi_indexed_ext.stride = stride;
    
       if (pVertexOffset) {
          cmd->u.draw_multi_indexed_ext.vertex_offset =
             vk_zalloc(cmd_buffer->cmd_queue.alloc,
                       sizeof(*cmd->u.draw_multi_indexed_ext.vertex_offset), 8,
                       VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
    
          memcpy(cmd->u.draw_multi_indexed_ext.vertex_offset, pVertexOffset,
                 sizeof(*cmd->u.draw_multi_indexed_ext.vertex_offset));
       }
    }
    
    static void
    push_descriptors_set_free(struct vk_cmd_queue *queue,
                              struct vk_cmd_queue_entry *cmd)
    {
       struct vk_command_buffer *cmd_buffer =
          container_of(queue, struct vk_command_buffer, cmd_queue);
       struct vk_cmd_push_descriptor_set *pds = &cmd->u.push_descriptor_set;
    
       VK_FROM_HANDLE(vk_pipeline_layout, vk_layout, pds->layout);
       vk_pipeline_layout_unref(cmd_buffer->base.device, vk_layout);
    
      for (unsigned i = 0; i < pds->descriptor_write_count; i++) {
        VkWriteDescriptorSet *entry = &pds->descriptor_writes[i];
        switch (entry->descriptorType) {
        case VK_DESCRIPTOR_TYPE_SAMPLER:
        case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
        case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
        case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
        case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
           vk_free(queue->alloc, (void *)entry->pImageInfo);
           break;
        case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
        case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
           vk_free(queue->alloc, (void *)entry->pTexelBufferView);
           break;
        case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
        case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
        case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
        case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
        default:
           vk_free(queue->alloc, (void *)entry->pBufferInfo);
           break;
        }
      }
    }
    
    VKAPI_ATTR void VKAPI_CALL
    vk_cmd_enqueue_CmdPushDescriptorSet(VkCommandBuffer commandBuffer,
                                        VkPipelineBindPoint pipelineBindPoint,
                                        VkPipelineLayout layout,
                                        uint32_t set,
                                        uint32_t descriptorWriteCount,
                                        const VkWriteDescriptorSet *pDescriptorWrites)
    {
       VK_FROM_HANDLE(vk_command_buffer, cmd_buffer, commandBuffer);
       struct vk_cmd_push_descriptor_set *pds;
    
       struct vk_cmd_queue_entry *cmd =
          vk_zalloc(cmd_buffer->cmd_queue.alloc, sizeof(*cmd), 8,
                    VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
       if (!cmd)
          return;
    
       pds = &cmd->u.push_descriptor_set;
    
       cmd->type = VK_CMD_PUSH_DESCRIPTOR_SET;
       cmd->driver_free_cb = push_descriptors_set_free;
       list_addtail(&cmd->cmd_link, &cmd_buffer->cmd_queue.cmds);
    
       pds->pipeline_bind_point = pipelineBindPoint;
       pds->set = set;
       pds->descriptor_write_count = descriptorWriteCount;
    
       /* From the application's perspective, the vk_cmd_queue_entry can outlive the
        * layout. Take a reference.
        */
       VK_FROM_HANDLE(vk_pipeline_layout, vk_layout, layout);
       pds->layout = layout;
       vk_pipeline_layout_ref(vk_layout);
    
       if (pDescriptorWrites) {
          pds->descriptor_writes =
             vk_zalloc(cmd_buffer->cmd_queue.alloc,
                       sizeof(*pds->descriptor_writes) * descriptorWriteCount, 8,
                       VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
          memcpy(pds->descriptor_writes,
                 pDescriptorWrites,
                 sizeof(*pds->descriptor_writes) * descriptorWriteCount);
    
          for (unsigned i = 0; i < descriptorWriteCount; i++) {
             switch (pds->descriptor_writes[i].descriptorType) {
             case VK_DESCRIPTOR_TYPE_SAMPLER:
             case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
             case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
             case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
             case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
                pds->descriptor_writes[i].pImageInfo =
                   vk_zalloc(cmd_buffer->cmd_queue.alloc,
                             sizeof(VkDescriptorImageInfo) * pds->descriptor_writes[i].descriptorCount, 8,
                             VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
                memcpy((VkDescriptorImageInfo *)pds->descriptor_writes[i].pImageInfo,
                       pDescriptorWrites[i].pImageInfo,
                       sizeof(VkDescriptorImageInfo) * pds->descriptor_writes[i].descriptorCount);
                break;
             case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
             case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
                pds->descriptor_writes[i].pTexelBufferView =
                   vk_zalloc(cmd_buffer->cmd_queue.alloc,
                             sizeof(VkBufferView) * pds->descriptor_writes[i].descriptorCount, 8,
                             VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
                memcpy((VkBufferView *)pds->descriptor_writes[i].pTexelBufferView,
                       pDescriptorWrites[i].pTexelBufferView,
                       sizeof(VkBufferView) * pds->descriptor_writes[i].descriptorCount);
                break;
             case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
             case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
             case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
             case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
             default:
                pds->descriptor_writes[i].pBufferInfo =
                   vk_zalloc(cmd_buffer->cmd_queue.alloc,
                             sizeof(VkDescriptorBufferInfo) * pds->descriptor_writes[i].descriptorCount, 8,
                             VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
                memcpy((VkDescriptorBufferInfo *)pds->descriptor_writes[i].pBufferInfo,
                       pDescriptorWrites[i].pBufferInfo,
                       sizeof(VkDescriptorBufferInfo) * pds->descriptor_writes[i].descriptorCount);
                break;
             }
          }
       }
    }
    
    static void
    unref_pipeline_layout(struct vk_cmd_queue *queue,
                          struct vk_cmd_queue_entry *cmd)
    {
       struct vk_command_buffer *cmd_buffer =
          container_of(queue, struct vk_command_buffer, cmd_queue);
       VK_FROM_HANDLE(vk_pipeline_layout, layout,
                      cmd->u.bind_descriptor_sets.layout);
    
       assert(cmd->type == VK_CMD_BIND_DESCRIPTOR_SETS);
    
       vk_pipeline_layout_unref(cmd_buffer->base.device, layout);
    }
    
    VKAPI_ATTR void VKAPI_CALL
    vk_cmd_enqueue_CmdBindDescriptorSets(VkCommandBuffer commandBuffer,
                                         VkPipelineBindPoint pipelineBindPoint,
                                         VkPipelineLayout layout,
                                         uint32_t firstSet,
                                         uint32_t descriptorSetCount,
                                         const VkDescriptorSet* pDescriptorSets,
                                         uint32_t dynamicOffsetCount,
                                         const uint32_t *pDynamicOffsets)
    {
       VK_FROM_HANDLE(vk_command_buffer, cmd_buffer, commandBuffer);
    
       struct vk_cmd_queue_entry *cmd =
          vk_zalloc(cmd_buffer->cmd_queue.alloc, sizeof(*cmd), 8,
                    VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
       if (!cmd)
          return;
    
       cmd->type = VK_CMD_BIND_DESCRIPTOR_SETS;
       list_addtail(&cmd->cmd_link, &cmd_buffer->cmd_queue.cmds);
    
       /* We need to hold a reference to the descriptor set as long as this
        * command is in the queue.  Otherwise, it may get deleted out from under
        * us before the command is replayed.
        */
       vk_pipeline_layout_ref(vk_pipeline_layout_from_handle(layout));
       cmd->u.bind_descriptor_sets.layout = layout;
       cmd->driver_free_cb = unref_pipeline_layout;
    
       cmd->u.bind_descriptor_sets.pipeline_bind_point = pipelineBindPoint;
       cmd->u.bind_descriptor_sets.first_set = firstSet;
       cmd->u.bind_descriptor_sets.descriptor_set_count = descriptorSetCount;
       if (pDescriptorSets) {
          cmd->u.bind_descriptor_sets.descriptor_sets =
             vk_zalloc(cmd_buffer->cmd_queue.alloc,
                       sizeof(*cmd->u.bind_descriptor_sets.descriptor_sets) * descriptorSetCount, 8,
                       VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
    
          memcpy(cmd->u.bind_descriptor_sets.descriptor_sets, pDescriptorSets,
                 sizeof(*cmd->u.bind_descriptor_sets.descriptor_sets) * descriptorSetCount);
       }
       cmd->u.bind_descriptor_sets.dynamic_offset_count = dynamicOffsetCount;
       if (pDynamicOffsets) {
          cmd->u.bind_descriptor_sets.dynamic_offsets =
             vk_zalloc(cmd_buffer->cmd_queue.alloc,
                       sizeof(*cmd->u.bind_descriptor_sets.dynamic_offsets) * dynamicOffsetCount, 8,
                       VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
    
          memcpy(cmd->u.bind_descriptor_sets.dynamic_offsets, pDynamicOffsets,
                 sizeof(*cmd->u.bind_descriptor_sets.dynamic_offsets) * dynamicOffsetCount);
       }
    }
    
    #ifdef VK_ENABLE_BETA_EXTENSIONS
    static void
    dispatch_graph_amdx_free(struct vk_cmd_queue *queue, struct vk_cmd_queue_entry *cmd)
    {
       VkDispatchGraphCountInfoAMDX *count_info = cmd->u.dispatch_graph_amdx.count_info;
       void *infos = (void *)count_info->infos.hostAddress;
    
       for (uint32_t i = 0; i < count_info->count; i++) {
          VkDispatchGraphInfoAMDX *info = (void *)((const uint8_t *)infos + i * count_info->stride);
          vk_free(queue->alloc, (void *)info->payloads.hostAddress);
       }
    
       vk_free(queue->alloc, infos);
    }
    
    VKAPI_ATTR void VKAPI_CALL
    vk_cmd_enqueue_CmdDispatchGraphAMDX(VkCommandBuffer commandBuffer, VkDeviceAddress scratch,
                                        VkDeviceSize scratchSize,
                                        const VkDispatchGraphCountInfoAMDX *pCountInfo)
    {
       VK_FROM_HANDLE(vk_command_buffer, cmd_buffer, commandBuffer);
    
       if (vk_command_buffer_has_error(cmd_buffer))
          return;
    
       VkResult result = VK_SUCCESS;
       const VkAllocationCallbacks *alloc = cmd_buffer->cmd_queue.alloc;
    
       struct vk_cmd_queue_entry *cmd =
          vk_zalloc(alloc, sizeof(struct vk_cmd_queue_entry), 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
       if (!cmd) {
          result = VK_ERROR_OUT_OF_HOST_MEMORY;
          goto err;
       }
    
       cmd->type = VK_CMD_DISPATCH_GRAPH_AMDX;
       cmd->driver_free_cb = dispatch_graph_amdx_free;
    
       cmd->u.dispatch_graph_amdx.scratch = scratch;
       cmd->u.dispatch_graph_amdx.scratch_size = scratchSize;
    
       cmd->u.dispatch_graph_amdx.count_info =
          vk_zalloc(alloc, sizeof(VkDispatchGraphCountInfoAMDX), 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
       if (cmd->u.dispatch_graph_amdx.count_info == NULL)
          goto err;
    
       memcpy((void *)cmd->u.dispatch_graph_amdx.count_info, pCountInfo,
              sizeof(VkDispatchGraphCountInfoAMDX));
    
       uint32_t infos_size = pCountInfo->count * pCountInfo->stride;
       void *infos = vk_zalloc(alloc, infos_size, 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
       cmd->u.dispatch_graph_amdx.count_info->infos.hostAddress = infos;
       memcpy(infos, pCountInfo->infos.hostAddress, infos_size);
    
       for (uint32_t i = 0; i < pCountInfo->count; i++) {
          VkDispatchGraphInfoAMDX *info = (void *)((const uint8_t *)infos + i * pCountInfo->stride);
    
          uint32_t payloads_size = info->payloadCount * info->payloadStride;
          void *dst_payload = vk_zalloc(alloc, payloads_size, 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
          memcpy(dst_payload, info->payloads.hostAddress, payloads_size);
          info->payloads.hostAddress = dst_payload;
       }
    
       list_addtail(&cmd->cmd_link, &cmd_buffer->cmd_queue.cmds);
       goto finish;
    err:
       if (cmd) {
          vk_free(alloc, cmd);
          dispatch_graph_amdx_free(&cmd_buffer->cmd_queue, cmd);
       }
    
    finish:
       if (unlikely(result != VK_SUCCESS))
          vk_command_buffer_set_error(cmd_buffer, result);
    }
    #endif
    
    static void
    vk_cmd_build_acceleration_structures_khr_free(struct vk_cmd_queue *queue,
                                                  struct vk_cmd_queue_entry *cmd)
    {
       struct vk_cmd_build_acceleration_structures_khr *build =
          &cmd->u.build_acceleration_structures_khr;
       
       for (uint32_t i = 0; i < build->info_count; i++) {
          vk_free(queue->alloc, (void *)build->infos[i].pGeometries);
          vk_free(queue->alloc, (void *)build->pp_build_range_infos[i]);
       }
    }
    
    VKAPI_ATTR void VKAPI_CALL
    vk_cmd_enqueue_CmdBuildAccelerationStructuresKHR(
       VkCommandBuffer commandBuffer, uint32_t infoCount,
       const VkAccelerationStructureBuildGeometryInfoKHR *pInfos,
       const VkAccelerationStructureBuildRangeInfoKHR *const *ppBuildRangeInfos)
    {
       VK_FROM_HANDLE(vk_command_buffer, cmd_buffer, commandBuffer);
    
       if (vk_command_buffer_has_error(cmd_buffer))
          return;
    
       struct vk_cmd_queue *queue = &cmd_buffer->cmd_queue;
    
       struct vk_cmd_queue_entry *cmd =
          vk_zalloc(queue->alloc, vk_cmd_queue_type_sizes[VK_CMD_BUILD_ACCELERATION_STRUCTURES_KHR], 8,
                    VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
       if (!cmd)
          goto err;
    
       cmd->type = VK_CMD_BUILD_ACCELERATION_STRUCTURES_KHR;
       cmd->driver_free_cb = vk_cmd_build_acceleration_structures_khr_free;
    
       struct vk_cmd_build_acceleration_structures_khr *build =
          &cmd->u.build_acceleration_structures_khr;
    
       build->info_count = infoCount;
       if (pInfos) {
          build->infos = vk_zalloc(queue->alloc, sizeof(*build->infos) * infoCount, 8,
                                   VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
          if (!build->infos)
             goto err;
    
          memcpy((VkAccelerationStructureBuildGeometryInfoKHR *)build->infos, pInfos,
                 sizeof(*build->infos) * (infoCount));
       
          for (uint32_t i = 0; i < infoCount; i++) {
             uint32_t geometries_size =
                build->infos[i].geometryCount * sizeof(VkAccelerationStructureGeometryKHR);
             VkAccelerationStructureGeometryKHR *geometries =
                vk_zalloc(queue->alloc, geometries_size, 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
             if (!geometries)
                goto err;
    
             if (pInfos[i].pGeometries) {
                memcpy(geometries, pInfos[i].pGeometries, geometries_size);
             } else {
                for (uint32_t j = 0; j < build->infos[i].geometryCount; j++)
                   memcpy(&geometries[j], pInfos[i].ppGeometries[j], sizeof(VkAccelerationStructureGeometryKHR));
             }
    
             build->infos[i].pGeometries = geometries;
          }
       }
       if (ppBuildRangeInfos) {
          build->pp_build_range_infos =
             vk_zalloc(queue->alloc, sizeof(*build->pp_build_range_infos) * infoCount, 8,
                       VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
          if (!build->pp_build_range_infos)
             goto err;
    
          VkAccelerationStructureBuildRangeInfoKHR **pp_build_range_infos =
             (void *)build->pp_build_range_infos;
    
          for (uint32_t i = 0; i < infoCount; i++) {
             uint32_t build_range_size =
                build->infos[i].geometryCount * sizeof(VkAccelerationStructureBuildRangeInfoKHR);
             VkAccelerationStructureBuildRangeInfoKHR *p_build_range_infos =
                vk_zalloc(queue->alloc, build_range_size, 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
             if (!p_build_range_infos)
                goto err;
    
             memcpy(p_build_range_infos, ppBuildRangeInfos[i], build_range_size);
    
             pp_build_range_infos[i] = p_build_range_infos;
          }
       }
    
       list_addtail(&cmd->cmd_link, &queue->cmds);
       return;
    
    err:
       if (cmd)
          vk_cmd_build_acceleration_structures_khr_free(queue, cmd);
    
       vk_command_buffer_set_error(cmd_buffer, VK_ERROR_OUT_OF_HOST_MEMORY);
    }
    
    VKAPI_ATTR void VKAPI_CALL vk_cmd_enqueue_CmdPushConstants2(
       VkCommandBuffer                             commandBuffer,
       const VkPushConstantsInfoKHR* pPushConstantsInfo)
    {
       VK_FROM_HANDLE(vk_command_buffer, cmd_buffer, commandBuffer);
       struct vk_cmd_queue *queue = &cmd_buffer->cmd_queue;
    
       struct vk_cmd_queue_entry *cmd = vk_zalloc(queue->alloc, vk_cmd_queue_type_sizes[VK_CMD_PUSH_CONSTANTS2], 8,
                                                  VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
       if (!cmd)
          return;
    
       cmd->type = VK_CMD_PUSH_CONSTANTS2;
    
       VkPushConstantsInfoKHR *info = vk_zalloc(queue->alloc, sizeof(*info), 8,
                                                VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
       void *pValues = vk_zalloc(queue->alloc, pPushConstantsInfo->size, 8,
                                 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
    
       memcpy(info, pPushConstantsInfo, sizeof(*info));
       memcpy(pValues, pPushConstantsInfo->pValues, pPushConstantsInfo->size);
    
       cmd->u.push_constants2.push_constants_info = info;
       info->pValues = pValues;
    
       list_addtail(&cmd->cmd_link, &cmd_buffer->cmd_queue.cmds);
    }
    
    static void
    vk_free_cmd_push_descriptor_set2(struct vk_cmd_queue *queue,
                                     struct vk_cmd_queue_entry *cmd)
    {
       ralloc_free(cmd->driver_data);
    }
    
    VKAPI_ATTR void VKAPI_CALL vk_cmd_enqueue_CmdPushDescriptorSet2(
        VkCommandBuffer                             commandBuffer,
        const VkPushDescriptorSetInfoKHR*           pPushDescriptorSetInfo)
    {
       VK_FROM_HANDLE(vk_command_buffer, cmd_buffer, commandBuffer);
       struct vk_cmd_queue_entry *cmd = vk_zalloc(cmd_buffer->cmd_queue.alloc, vk_cmd_queue_type_sizes[VK_CMD_PUSH_DESCRIPTOR_SET2], 8,
                                                  VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
    
       cmd->type = VK_CMD_PUSH_DESCRIPTOR_SET2;
       cmd->driver_free_cb = vk_free_cmd_push_descriptor_set2;
    
       void *ctx = cmd->driver_data = ralloc_context(NULL);
       if (pPushDescriptorSetInfo) {
          cmd->u.push_descriptor_set2.push_descriptor_set_info = vk_zalloc(cmd_buffer->cmd_queue.alloc, sizeof(VkPushDescriptorSetInfoKHR), 8,
                                                                               VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
    
          memcpy((void*)cmd->u.push_descriptor_set2.push_descriptor_set_info, pPushDescriptorSetInfo, sizeof(VkPushDescriptorSetInfoKHR));
          VkPushDescriptorSetInfoKHR *tmp_dst1 = (void *) cmd->u.push_descriptor_set2.push_descriptor_set_info; (void) tmp_dst1;
          VkPushDescriptorSetInfoKHR *tmp_src1 = (void *) pPushDescriptorSetInfo; (void) tmp_src1;
    
          const VkBaseInStructure *pnext = tmp_dst1->pNext;
          if (pnext) {
             switch ((int32_t)pnext->sType) {
             case VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO:
                if (pnext) {
                   tmp_dst1->pNext = rzalloc(ctx, VkPipelineLayoutCreateInfo);
    
                   memcpy((void*)tmp_dst1->pNext, pnext, sizeof(VkPipelineLayoutCreateInfo));
                   VkPipelineLayoutCreateInfo *tmp_dst2 = (void *) tmp_dst1->pNext; (void) tmp_dst2;
                   VkPipelineLayoutCreateInfo *tmp_src2 = (void *) pnext; (void) tmp_src2;
                   if (tmp_src2->pSetLayouts) {
                      tmp_dst2->pSetLayouts = rzalloc_array_size(ctx, sizeof(*tmp_dst2->pSetLayouts), tmp_dst2->setLayoutCount);
    
                      memcpy((void*)tmp_dst2->pSetLayouts, tmp_src2->pSetLayouts, sizeof(*tmp_dst2->pSetLayouts) * tmp_dst2->setLayoutCount);
                   }
                   if (tmp_src2->pPushConstantRanges) {
                      tmp_dst2->pPushConstantRanges = rzalloc_array_size(ctx, sizeof(*tmp_dst2->pPushConstantRanges), tmp_dst2->pushConstantRangeCount);
    
                      memcpy((void*)tmp_dst2->pPushConstantRanges, tmp_src2->pPushConstantRanges, sizeof(*tmp_dst2->pPushConstantRanges) * tmp_dst2->pushConstantRangeCount);
                   }
    
                } else {
                   tmp_dst1->pNext = NULL;
                }
                break;
             }
          }
          if (tmp_src1->pDescriptorWrites) {
             tmp_dst1->pDescriptorWrites = vk_zalloc(cmd_buffer->cmd_queue.alloc, sizeof(*tmp_dst1->pDescriptorWrites) * tmp_dst1->descriptorWriteCount, 8,
                                                     VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
    
             memcpy((void*)tmp_dst1->pDescriptorWrites, tmp_src1->pDescriptorWrites, sizeof(*tmp_dst1->pDescriptorWrites) * tmp_dst1->descriptorWriteCount);
             for (unsigned i = 0; i < tmp_src1->descriptorWriteCount; i++) {
                VkWriteDescriptorSet *dstwrite = (void*)&tmp_dst1->pDescriptorWrites[i];
                const VkWriteDescriptorSet *write = &tmp_src1->pDescriptorWrites[i];
                switch (write->descriptorType) {
                case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK: {
                   const VkWriteDescriptorSetInlineUniformBlock *uniform_data = vk_find_struct_const(write->pNext, WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK);
                   assert(uniform_data);
                   VkWriteDescriptorSetInlineUniformBlock *dst = rzalloc(ctx, VkWriteDescriptorSetInlineUniformBlock);
                   memcpy((void*)dst, uniform_data, sizeof(*uniform_data));
                   dst->pData = ralloc_size(ctx, uniform_data->dataSize);
                   memcpy((void*)dst->pData, uniform_data->pData, uniform_data->dataSize);
                   dstwrite->pNext = dst;
                   break;
                }
    
                case VK_DESCRIPTOR_TYPE_SAMPLER:
                case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
                case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
                case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
                case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
                   dstwrite->pImageInfo = rzalloc_array(ctx, VkDescriptorImageInfo, write->descriptorCount);
                   {
                      VkDescriptorImageInfo *arr = (void*)dstwrite->pImageInfo;
                      typed_memcpy(arr, write->pImageInfo, write->descriptorCount);
                   }
                   break;
    
                case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
                case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
                   dstwrite->pTexelBufferView = rzalloc_array(ctx, VkBufferView, write->descriptorCount);
                   {
                      VkBufferView *arr = (void*)dstwrite->pTexelBufferView;
                      typed_memcpy(arr, write->pTexelBufferView, write->descriptorCount);
                   }
                   break;
    
                case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
                case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
                case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
                case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
                   dstwrite->pBufferInfo = rzalloc_array(ctx, VkDescriptorBufferInfo, write->descriptorCount);
                   {
                      VkDescriptorBufferInfo *arr = (void*)dstwrite->pBufferInfo;
                      typed_memcpy(arr, write->pBufferInfo, write->descriptorCount);
                   }
                   break;
    
                case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR: {
                   const VkWriteDescriptorSetAccelerationStructureKHR *accel_structs =
                      vk_find_struct_const(write->pNext, WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR);
    
                   uint32_t accel_structs_size = sizeof(VkAccelerationStructureKHR) * accel_structs->accelerationStructureCount;
                   VkWriteDescriptorSetAccelerationStructureKHR *write_accel_structs =
                      rzalloc_size(ctx, sizeof(VkWriteDescriptorSetAccelerationStructureKHR) + accel_structs_size);
    
                   write_accel_structs->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR;
                   write_accel_structs->accelerationStructureCount = accel_structs->accelerationStructureCount;
                   write_accel_structs->pAccelerationStructures = (void *)&write_accel_structs[1];
                   memcpy((void *)write_accel_structs->pAccelerationStructures, accel_structs->pAccelerationStructures, accel_structs_size);
    
                   dstwrite->pNext = write_accel_structs;
                   break;
                }
    
                default:
                   break;
                }
             }
          }
       }
    
       list_addtail(&cmd->cmd_link, &cmd_buffer->cmd_queue.cmds);
    }