vulkan: Adds helpers for vk_object (de)alloation and (de)initialization.
[mesa.git] / src / vulkan / util / vk_object.c
1 /*
2 * Copyright © 2020 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 #include "vk_object.h"
25
26 #include "vk_alloc.h"
27 #include "util/hash_table.h"
28 #include "util/ralloc.h"
29
30 void
31 vk_object_base_init(UNUSED struct vk_device *device,
32 struct vk_object_base *base,
33 UNUSED VkObjectType obj_type)
34 {
35 base->_loader_data.loaderMagic = ICD_LOADER_MAGIC;
36 base->type = obj_type;
37 util_sparse_array_init(&base->private_data, sizeof(uint64_t), 8);
38 }
39
40 void
41 vk_object_base_finish(struct vk_object_base *base)
42 {
43 util_sparse_array_finish(&base->private_data);
44 }
45
46 void
47 vk_device_init(struct vk_device *device,
48 UNUSED const VkDeviceCreateInfo *pCreateInfo,
49 const VkAllocationCallbacks *instance_alloc,
50 const VkAllocationCallbacks *device_alloc)
51 {
52 vk_object_base_init(device, &device->base, VK_OBJECT_TYPE_DEVICE);
53 if (device_alloc)
54 device->alloc = *device_alloc;
55 else
56 device->alloc = *instance_alloc;
57
58 p_atomic_set(&device->private_data_next_index, 0);
59
60 #ifdef ANDROID
61 mtx_init(&device->swapchain_private_mtx, mtx_plain);
62 device->swapchain_private = NULL;
63 #endif /* ANDROID */
64 }
65
66 void
67 vk_device_finish(UNUSED struct vk_device *device)
68 {
69 #ifdef ANDROID
70 if (device->swapchain_private) {
71 hash_table_foreach(device->swapchain_private, entry)
72 util_sparse_array_finish(entry->data);
73 ralloc_free(device->swapchain_private);
74 }
75 #endif /* ANDROID */
76
77 vk_object_base_finish(&device->base);
78 }
79
80 void *
81 vk_object_alloc(struct vk_device *device,
82 const VkAllocationCallbacks *alloc,
83 size_t size,
84 VkObjectType obj_type)
85 {
86 void *ptr = vk_alloc2(&device->alloc, alloc, size, 8,
87 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
88 if (ptr == NULL)
89 return NULL;
90
91 vk_object_base_init(device, (struct vk_object_base *)ptr, obj_type);
92
93 return ptr;
94 }
95
96 void *
97 vk_object_zalloc(struct vk_device *device,
98 const VkAllocationCallbacks *alloc,
99 size_t size,
100 VkObjectType obj_type)
101 {
102 void *ptr = vk_zalloc2(&device->alloc, alloc, size, 8,
103 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
104 if (ptr == NULL)
105 return NULL;
106
107 vk_object_base_init(device, (struct vk_object_base *)ptr, obj_type);
108
109 return ptr;
110 }
111
112 void
113 vk_object_free(struct vk_device *device,
114 const VkAllocationCallbacks *alloc,
115 void *data)
116 {
117 vk_object_base_finish((struct vk_object_base *)data);
118 vk_free2(&device->alloc, alloc, data);
119 }
120
121 VkResult
122 vk_private_data_slot_create(struct vk_device *device,
123 const VkPrivateDataSlotCreateInfoEXT* pCreateInfo,
124 const VkAllocationCallbacks* pAllocator,
125 VkPrivateDataSlotEXT* pPrivateDataSlot)
126 {
127 struct vk_private_data_slot *slot =
128 vk_alloc2(&device->alloc, pAllocator, sizeof(*slot), 8,
129 VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
130 if (slot == NULL)
131 return VK_ERROR_OUT_OF_HOST_MEMORY;
132
133 vk_object_base_init(device, &slot->base,
134 VK_OBJECT_TYPE_PRIVATE_DATA_SLOT_EXT);
135 slot->index = p_atomic_inc_return(&device->private_data_next_index);
136
137 *pPrivateDataSlot = vk_private_data_slot_to_handle(slot);
138
139 return VK_SUCCESS;
140 }
141
142 void
143 vk_private_data_slot_destroy(struct vk_device *device,
144 VkPrivateDataSlotEXT privateDataSlot,
145 const VkAllocationCallbacks *pAllocator)
146 {
147 VK_FROM_HANDLE(vk_private_data_slot, slot, privateDataSlot);
148 if (slot == NULL)
149 return;
150
151 vk_object_base_finish(&slot->base);
152 vk_free2(&device->alloc, pAllocator, slot);
153 }
154
155 #ifdef ANDROID
156 static VkResult
157 get_swapchain_private_data_locked(struct vk_device *device,
158 uint64_t objectHandle,
159 struct vk_private_data_slot *slot,
160 uint64_t **private_data)
161 {
162 if (unlikely(device->swapchain_private == NULL)) {
163 /* Even though VkSwapchain is a non-dispatchable object, we know a
164 * priori that Android swapchains are actually pointers so we can use
165 * the pointer hash table for them.
166 */
167 device->swapchain_private = _mesa_pointer_hash_table_create(NULL);
168 if (device->swapchain_private == NULL)
169 return VK_ERROR_OUT_OF_HOST_MEMORY;
170 }
171
172 struct hash_entry *entry =
173 _mesa_hash_table_search(device->swapchain_private,
174 (void *)(uintptr_t)objectHandle);
175 if (unlikely(entry == NULL)) {
176 struct util_sparse_array *swapchain_private =
177 ralloc(device->swapchain_private, struct util_sparse_array);
178 util_sparse_array_init(swapchain_private, sizeof(uint64_t), 8);
179
180 entry = _mesa_hash_table_insert(device->swapchain_private,
181 (void *)(uintptr_t)objectHandle,
182 swapchain_private);
183 if (entry == NULL)
184 return VK_ERROR_OUT_OF_HOST_MEMORY;
185 }
186
187 struct util_sparse_array *swapchain_private = entry->data;
188 *private_data = util_sparse_array_get(swapchain_private, slot->index);
189
190 return VK_SUCCESS;
191 }
192 #endif /* ANDROID */
193
194 static VkResult
195 vk_object_base_private_data(struct vk_device *device,
196 VkObjectType objectType,
197 uint64_t objectHandle,
198 VkPrivateDataSlotEXT privateDataSlot,
199 uint64_t **private_data)
200 {
201 VK_FROM_HANDLE(vk_private_data_slot, slot, privateDataSlot);
202
203 #ifdef ANDROID
204 /* There is an annoying spec corner here on Android. Because WSI is
205 * implemented in the Vulkan loader which doesn't know about the
206 * VK_EXT_private_data extension, we have to handle VkSwapchainKHR in the
207 * driver as a special case. On future versions of Android where the
208 * loader does understand VK_EXT_private_data, we'll never see a
209 * vkGet/SetPrivateDataEXT call on a swapchain because the loader will
210 * handle it.
211 */
212 if (objectType == VK_OBJECT_TYPE_SWAPCHAIN_KHR) {
213 mtx_lock(&device->swapchain_private_mtx);
214 VkResult result = get_swapchain_private_data_locked(device, objectHandle,
215 slot, private_data);
216 mtx_unlock(&device->swapchain_private_mtx);
217 return result;
218 }
219 #endif /* ANDROID */
220
221 struct vk_object_base *obj =
222 vk_object_base_from_u64_handle(objectHandle, objectType);
223 *private_data = util_sparse_array_get(&obj->private_data, slot->index);
224
225 return VK_SUCCESS;
226 }
227
228 VkResult
229 vk_object_base_set_private_data(struct vk_device *device,
230 VkObjectType objectType,
231 uint64_t objectHandle,
232 VkPrivateDataSlotEXT privateDataSlot,
233 uint64_t data)
234 {
235 uint64_t *private_data;
236 VkResult result = vk_object_base_private_data(device,
237 objectType, objectHandle,
238 privateDataSlot,
239 &private_data);
240 if (unlikely(result != VK_SUCCESS))
241 return result;
242
243 *private_data = data;
244 return VK_SUCCESS;
245 }
246
247 void
248 vk_object_base_get_private_data(struct vk_device *device,
249 VkObjectType objectType,
250 uint64_t objectHandle,
251 VkPrivateDataSlotEXT privateDataSlot,
252 uint64_t *pData)
253 {
254 uint64_t *private_data;
255 VkResult result = vk_object_base_private_data(device,
256 objectType, objectHandle,
257 privateDataSlot,
258 &private_data);
259 if (likely(result == VK_SUCCESS)) {
260 *pData = *private_data;
261 } else {
262 *pData = 0;
263 }
264 }