Edit

IABSD.fr/xenocara/lib/mesa/src/vulkan/runtime/vk_command_pool.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_command_pool.c
  • /*
     * Copyright © 2015 Intel Corporation
     * 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_command_pool.h"
    
    #include "vk_alloc.h"
    #include "vk_command_buffer.h"
    #include "vk_common_entrypoints.h"
    #include "vk_device.h"
    #include "vk_log.h"
    
    static bool
    should_recycle_command_buffers(struct vk_device *device)
    {
       /* They have to be using the common allocation implementation, otherwise
        * the recycled command buffers will never actually get re-used
        */
       const struct vk_device_dispatch_table *disp = &device->dispatch_table;
       if (disp->AllocateCommandBuffers != vk_common_AllocateCommandBuffers)
          return false;
    
       /* We need to be able to reset command buffers */
       if (device->command_buffer_ops->reset == NULL)
          return false;
    
       return true;
    }
    
    static void
    destroy_free_command_buffers(struct vk_command_pool *pool)
    {
       for (uint32_t i = 0; i < ARRAY_SIZE(pool->free_command_buffers); i++) {
          list_for_each_entry_safe(struct vk_command_buffer, cmd_buffer,
                                   &pool->free_command_buffers[i], pool_link) {
             cmd_buffer->ops->destroy(cmd_buffer);
          }
          assert(list_is_empty(&pool->free_command_buffers[i]));
       }
    }
    
    VkResult MUST_CHECK
    vk_command_pool_init(struct vk_device *device,
                         struct vk_command_pool *pool,
                         const VkCommandPoolCreateInfo *pCreateInfo,
                         const VkAllocationCallbacks *pAllocator)
    {
       memset(pool, 0, sizeof(*pool));
       vk_object_base_init(device, &pool->base,
                           VK_OBJECT_TYPE_COMMAND_POOL);
    
       pool->flags = pCreateInfo->flags;
       pool->queue_family_index = pCreateInfo->queueFamilyIndex;
       pool->alloc = pAllocator ? *pAllocator : device->alloc;
       pool->command_buffer_ops = device->command_buffer_ops;
       pool->recycle_command_buffers = should_recycle_command_buffers(device);
       list_inithead(&pool->command_buffers);
    
       for (uint32_t i = 0; i < ARRAY_SIZE(pool->free_command_buffers); i++)
          list_inithead(&pool->free_command_buffers[i]);
    
       return VK_SUCCESS;
    }
    
    void
    vk_command_pool_finish(struct vk_command_pool *pool)
    {
       list_for_each_entry_safe(struct vk_command_buffer, cmd_buffer,
                                &pool->command_buffers, pool_link) {
          cmd_buffer->ops->destroy(cmd_buffer);
       }
       assert(list_is_empty(&pool->command_buffers));
    
       destroy_free_command_buffers(pool);
    
       vk_object_base_finish(&pool->base);
    }
    
    VKAPI_ATTR VkResult VKAPI_CALL
    vk_common_CreateCommandPool(VkDevice _device,
                                const VkCommandPoolCreateInfo *pCreateInfo,
                                const VkAllocationCallbacks *pAllocator,
                                VkCommandPool *pCommandPool)
    {
       VK_FROM_HANDLE(vk_device, device, _device);
       struct vk_command_pool *pool;
       VkResult result;
    
       pool = vk_alloc2(&device->alloc, pAllocator, sizeof(*pool), 8,
                        VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
       if (pool == NULL)
          return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
    
       result = vk_command_pool_init(device, pool, pCreateInfo, pAllocator);
       if (unlikely(result != VK_SUCCESS)) {
          vk_free2(&device->alloc, pAllocator, pool);
          return result;
       }
    
       *pCommandPool = vk_command_pool_to_handle(pool);
    
       return VK_SUCCESS;
    }
    
    VKAPI_ATTR void VKAPI_CALL
    vk_common_DestroyCommandPool(VkDevice _device,
                                 VkCommandPool commandPool,
                                 const VkAllocationCallbacks *pAllocator)
    {
       VK_FROM_HANDLE(vk_device, device, _device);
       VK_FROM_HANDLE(vk_command_pool, pool, commandPool);
    
       if (pool == NULL)
          return;
    
       vk_command_pool_finish(pool);
       vk_free2(&device->alloc, pAllocator, pool);
    }
    
    VKAPI_ATTR VkResult VKAPI_CALL
    vk_common_ResetCommandPool(VkDevice device,
                               VkCommandPool commandPool,
                               VkCommandPoolResetFlags flags)
    {
       VK_FROM_HANDLE(vk_command_pool, pool, commandPool);
       const struct vk_device_dispatch_table *disp =
          &pool->base.device->dispatch_table;
    
    #define COPY_FLAG(flag) \
       if (flags & VK_COMMAND_POOL_RESET_##flag) \
          cb_flags |= VK_COMMAND_BUFFER_RESET_##flag
    
       VkCommandBufferResetFlags cb_flags = 0;
       COPY_FLAG(RELEASE_RESOURCES_BIT);
    
    #undef COPY_FLAG
    
       list_for_each_entry_safe(struct vk_command_buffer, cmd_buffer,
                                &pool->command_buffers, pool_link) {
          VkResult result =
             disp->ResetCommandBuffer(vk_command_buffer_to_handle(cmd_buffer),
                                      cb_flags);
          if (result != VK_SUCCESS)
             return result;
       }
    
       return VK_SUCCESS;
    }
    
    static void
    vk_command_buffer_recycle_or_destroy(struct vk_command_pool *pool,
                                         struct vk_command_buffer *cmd_buffer)
    {
       assert(pool == cmd_buffer->pool);
    
       if (pool->recycle_command_buffers) {
          vk_command_buffer_recycle(cmd_buffer);
    
          list_del(&cmd_buffer->pool_link);
          list_add(&cmd_buffer->pool_link, &pool->free_command_buffers[cmd_buffer->level]);
       } else {
          cmd_buffer->ops->destroy(cmd_buffer);
       }
    }
    
    static struct vk_command_buffer *
    vk_command_pool_find_free(struct vk_command_pool *pool,
                              VkCommandBufferLevel level)
    {
       if (list_is_empty(&pool->free_command_buffers[level]))
          return NULL;
    
       struct vk_command_buffer *cmd_buffer =
          list_first_entry(&pool->free_command_buffers[level],
                           struct vk_command_buffer, pool_link);
    
       list_del(&cmd_buffer->pool_link);
       list_addtail(&cmd_buffer->pool_link, &pool->command_buffers);
    
       return cmd_buffer;
    }
    
    VKAPI_ATTR VkResult VKAPI_CALL
    vk_common_AllocateCommandBuffers(VkDevice device,
                                     const VkCommandBufferAllocateInfo *pAllocateInfo,
                                     VkCommandBuffer *pCommandBuffers)
    {
       VK_FROM_HANDLE(vk_command_pool, pool, pAllocateInfo->commandPool);
       VkResult result;
       uint32_t i;
    
       assert(device == vk_device_to_handle(pool->base.device));
    
       for (i = 0; i < pAllocateInfo->commandBufferCount; i++) {
          struct vk_command_buffer *cmd_buffer =
             vk_command_pool_find_free(pool, pAllocateInfo->level);
          if (cmd_buffer == NULL) {
             result = pool->command_buffer_ops->create(pool, pAllocateInfo->level, &cmd_buffer);
             if (unlikely(result != VK_SUCCESS))
                goto fail;
          }
    
          cmd_buffer->level = pAllocateInfo->level;
    
          pCommandBuffers[i] = vk_command_buffer_to_handle(cmd_buffer);
       }
    
       return VK_SUCCESS;
    
    fail:
       while (i--) {
          VK_FROM_HANDLE(vk_command_buffer, cmd_buffer, pCommandBuffers[i]);
          vk_command_buffer_recycle_or_destroy(pool, cmd_buffer);
       }
       for (i = 0; i < pAllocateInfo->commandBufferCount; i++)
          pCommandBuffers[i] = VK_NULL_HANDLE;
    
       return result;
    }
    
    VKAPI_ATTR void VKAPI_CALL
    vk_common_FreeCommandBuffers(VkDevice device,
                                 VkCommandPool commandPool,
                                 uint32_t commandBufferCount,
                                 const VkCommandBuffer *pCommandBuffers)
    {
       VK_FROM_HANDLE(vk_command_pool, pool, commandPool);
    
       for (uint32_t i = 0; i < commandBufferCount; i++) {
          VK_FROM_HANDLE(vk_command_buffer, cmd_buffer, pCommandBuffers[i]);
    
          if (cmd_buffer == NULL)
             continue;
    
          vk_command_buffer_recycle_or_destroy(pool, cmd_buffer);
       }
    }
    
    void
    vk_command_pool_trim(struct vk_command_pool *pool,
                         VkCommandPoolTrimFlags flags)
    {
       destroy_free_command_buffers(pool);
    }
    
    VKAPI_ATTR void VKAPI_CALL
    vk_common_TrimCommandPool(VkDevice device,
                              VkCommandPool commandPool,
                              VkCommandPoolTrimFlags flags)
    {
       VK_FROM_HANDLE(vk_command_pool, pool, commandPool);
    
       vk_command_pool_trim(pool, flags);
    }