1/*
2 * Copyright © 2015 Intel Corporation
3 * Copyright © 2022 Collabora, Ltd
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 * IN THE SOFTWARE.
23 */
24
25#include "vk_command_pool.h"
26
27#include "vk_alloc.h"
28#include "vk_command_buffer.h"
29#include "vk_common_entrypoints.h"
30#include "vk_device.h"
31#include "vk_log.h"
32
33VkResult MUST_CHECK
34vk_command_pool_init(struct vk_command_pool *pool,
35                     struct vk_device *device,
36                     const VkCommandPoolCreateInfo *pCreateInfo,
37                     const VkAllocationCallbacks *pAllocator)
38{
39   memset(pool, 0, sizeof(*pool));
40   vk_object_base_init(device, &pool->base,
41                       VK_OBJECT_TYPE_COMMAND_POOL);
42
43   pool->flags = pCreateInfo->flags;
44   pool->queue_family_index = pCreateInfo->queueFamilyIndex;
45   pool->alloc = pAllocator ? *pAllocator : device->alloc;
46   list_inithead(&pool->command_buffers);
47
48   return VK_SUCCESS;
49}
50
51void
52vk_command_pool_finish(struct vk_command_pool *pool)
53{
54   list_for_each_entry_safe(struct vk_command_buffer, cmd_buffer,
55                            &pool->command_buffers, pool_link) {
56      cmd_buffer->destroy(cmd_buffer);
57   }
58   assert(list_is_empty(&pool->command_buffers));
59
60   vk_object_base_finish(&pool->base);
61}
62
63VKAPI_ATTR VkResult VKAPI_CALL
64vk_common_CreateCommandPool(VkDevice _device,
65                            const VkCommandPoolCreateInfo *pCreateInfo,
66                            const VkAllocationCallbacks *pAllocator,
67                            VkCommandPool *pCommandPool)
68{
69   VK_FROM_HANDLE(vk_device, device, _device);
70   struct vk_command_pool *pool;
71   VkResult result;
72
73   pool = vk_alloc2(&device->alloc, pAllocator, sizeof(*pool), 8,
74                    VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
75   if (pool == NULL)
76      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
77
78   result = vk_command_pool_init(pool, device, pCreateInfo, pAllocator);
79   if (unlikely(result != VK_SUCCESS)) {
80      vk_free2(&device->alloc, pAllocator, pool);
81      return result;
82   }
83
84   *pCommandPool = vk_command_pool_to_handle(pool);
85
86   return VK_SUCCESS;
87}
88
89VKAPI_ATTR void VKAPI_CALL
90vk_common_DestroyCommandPool(VkDevice _device,
91                             VkCommandPool commandPool,
92                             const VkAllocationCallbacks *pAllocator)
93{
94   VK_FROM_HANDLE(vk_device, device, _device);
95   VK_FROM_HANDLE(vk_command_pool, pool, commandPool);
96
97   if (pool == NULL)
98      return;
99
100   vk_command_pool_finish(pool);
101   vk_free2(&device->alloc, pAllocator, pool);
102}
103
104VKAPI_ATTR VkResult VKAPI_CALL
105vk_common_ResetCommandPool(VkDevice device,
106                           VkCommandPool commandPool,
107                           VkCommandPoolResetFlags flags)
108{
109   VK_FROM_HANDLE(vk_command_pool, pool, commandPool);
110   const struct vk_device_dispatch_table *disp =
111      &pool->base.device->dispatch_table;
112
113#define COPY_FLAG(flag) \
114   if (flags & VK_COMMAND_POOL_RESET_##flag) \
115      cb_flags |= VK_COMMAND_BUFFER_RESET_##flag
116
117   VkCommandBufferResetFlags cb_flags = 0;
118   COPY_FLAG(RELEASE_RESOURCES_BIT);
119
120#undef COPY_FLAG
121
122   list_for_each_entry_safe(struct vk_command_buffer, cmd_buffer,
123                            &pool->command_buffers, pool_link) {
124      VkResult result =
125         disp->ResetCommandBuffer(vk_command_buffer_to_handle(cmd_buffer),
126                                  cb_flags);
127      if (result != VK_SUCCESS)
128         return result;
129   }
130
131   return VK_SUCCESS;
132}
133
134VKAPI_ATTR void VKAPI_CALL
135vk_common_FreeCommandBuffers(VkDevice device,
136                             VkCommandPool commandPool,
137                             uint32_t commandBufferCount,
138                             const VkCommandBuffer *pCommandBuffers)
139{
140   for (uint32_t i = 0; i < commandBufferCount; i++) {
141      VK_FROM_HANDLE(vk_command_buffer, cmd_buffer, pCommandBuffers[i]);
142
143      if (cmd_buffer == NULL)
144         continue;
145
146      cmd_buffer->destroy(cmd_buffer);
147   }
148}
149
150VKAPI_ATTR void VKAPI_CALL
151vk_common_TrimCommandPool(VkDevice device,
152                          VkCommandPool commandPool,
153                          VkCommandPoolTrimFlags flags)
154{
155   /* No-op is a valid implementation but may not be optimal */
156}
157