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 "vk_common_entrypoints.h"
28 #include "vk_instance.h"
29 #include "vk_device.h"
30 #include "util/hash_table.h"
31 #include "util/ralloc.h"
32 #include "vk_enum_to_str.h"
33
34 void
vk_object_base_init(struct vk_device * device,struct vk_object_base * base,VkObjectType obj_type)35 vk_object_base_init(struct vk_device *device,
36 struct vk_object_base *base,
37 VkObjectType obj_type)
38 {
39 base->_loader_data.loaderMagic = ICD_LOADER_MAGIC;
40 base->type = obj_type;
41 base->client_visible = false;
42 base->device = device;
43 base->instance = NULL;
44 base->object_name = NULL;
45 util_sparse_array_init(&base->private_data, sizeof(uint64_t), 8);
46 }
47
vk_object_base_instance_init(struct vk_instance * instance,struct vk_object_base * base,VkObjectType obj_type)48 void vk_object_base_instance_init(struct vk_instance *instance,
49 struct vk_object_base *base,
50 VkObjectType obj_type)
51 {
52 base->_loader_data.loaderMagic = ICD_LOADER_MAGIC;
53 base->type = obj_type;
54 base->client_visible = false;
55 base->device = NULL;
56 base->instance = instance;
57 base->object_name = NULL;
58 util_sparse_array_init(&base->private_data, sizeof(uint64_t), 8);
59 }
60
61 void
vk_object_base_finish(struct vk_object_base * base)62 vk_object_base_finish(struct vk_object_base *base)
63 {
64 util_sparse_array_finish(&base->private_data);
65
66 if (base->object_name == NULL)
67 return;
68
69 assert(base->device != NULL || base->instance != NULL);
70 if (base->device)
71 vk_free(&base->device->alloc, base->object_name);
72 else
73 vk_free(&base->instance->alloc, base->object_name);
74 }
75
76 void
vk_object_base_recycle(struct vk_object_base * base)77 vk_object_base_recycle(struct vk_object_base *base)
78 {
79 struct vk_device *device = base->device;
80 VkObjectType obj_type = base->type;
81 vk_object_base_finish(base);
82 vk_object_base_init(device, base, obj_type);
83 }
84
85 void *
vk_object_alloc(struct vk_device * device,const VkAllocationCallbacks * alloc,size_t size,VkObjectType obj_type)86 vk_object_alloc(struct vk_device *device,
87 const VkAllocationCallbacks *alloc,
88 size_t size,
89 VkObjectType obj_type)
90 {
91 void *ptr = vk_alloc2(&device->alloc, alloc, size, 8,
92 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
93 if (ptr == NULL)
94 return NULL;
95
96 vk_object_base_init(device, (struct vk_object_base *)ptr, obj_type);
97
98 return ptr;
99 }
100
101 void *
vk_object_zalloc(struct vk_device * device,const VkAllocationCallbacks * alloc,size_t size,VkObjectType obj_type)102 vk_object_zalloc(struct vk_device *device,
103 const VkAllocationCallbacks *alloc,
104 size_t size,
105 VkObjectType obj_type)
106 {
107 void *ptr = vk_zalloc2(&device->alloc, alloc, size, 8,
108 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
109 if (ptr == NULL)
110 return NULL;
111
112 vk_object_base_init(device, (struct vk_object_base *)ptr, obj_type);
113
114 return ptr;
115 }
116
117 void *
vk_object_multialloc(struct vk_device * device,struct vk_multialloc * ma,const VkAllocationCallbacks * alloc,VkObjectType obj_type)118 vk_object_multialloc(struct vk_device *device,
119 struct vk_multialloc *ma,
120 const VkAllocationCallbacks *alloc,
121 VkObjectType obj_type)
122 {
123 void *ptr = vk_multialloc_alloc2(ma, &device->alloc, alloc,
124 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
125 if (ptr == NULL)
126 return NULL;
127
128 vk_object_base_init(device, (struct vk_object_base *)ptr, obj_type);
129
130 return ptr;
131 }
132
133 void *
vk_object_multizalloc(struct vk_device * device,struct vk_multialloc * ma,const VkAllocationCallbacks * alloc,VkObjectType obj_type)134 vk_object_multizalloc(struct vk_device *device,
135 struct vk_multialloc *ma,
136 const VkAllocationCallbacks *alloc,
137 VkObjectType obj_type)
138 {
139 void *ptr = vk_multialloc_zalloc2(ma, &device->alloc, alloc,
140 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
141 if (ptr == NULL)
142 return NULL;
143
144 vk_object_base_init(device, (struct vk_object_base *)ptr, obj_type);
145
146 return ptr;
147 }
148
149 void
vk_object_free(struct vk_device * device,const VkAllocationCallbacks * alloc,void * data)150 vk_object_free(struct vk_device *device,
151 const VkAllocationCallbacks *alloc,
152 void *data)
153 {
154 vk_object_base_finish((struct vk_object_base *)data);
155 vk_free2(&device->alloc, alloc, data);
156 }
157
158 VkResult
vk_private_data_slot_create(struct vk_device * device,const VkPrivateDataSlotCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkPrivateDataSlot * pPrivateDataSlot)159 vk_private_data_slot_create(struct vk_device *device,
160 const VkPrivateDataSlotCreateInfo* pCreateInfo,
161 const VkAllocationCallbacks* pAllocator,
162 VkPrivateDataSlot* pPrivateDataSlot)
163 {
164 struct vk_private_data_slot *slot =
165 vk_alloc2(&device->alloc, pAllocator, sizeof(*slot), 8,
166 VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
167 if (slot == NULL)
168 return VK_ERROR_OUT_OF_HOST_MEMORY;
169
170 vk_object_base_init(device, &slot->base,
171 VK_OBJECT_TYPE_PRIVATE_DATA_SLOT);
172 slot->index = p_atomic_inc_return(&device->private_data_next_index);
173
174 *pPrivateDataSlot = vk_private_data_slot_to_handle(slot);
175
176 return VK_SUCCESS;
177 }
178
179 void
vk_private_data_slot_destroy(struct vk_device * device,VkPrivateDataSlot privateDataSlot,const VkAllocationCallbacks * pAllocator)180 vk_private_data_slot_destroy(struct vk_device *device,
181 VkPrivateDataSlot privateDataSlot,
182 const VkAllocationCallbacks *pAllocator)
183 {
184 VK_FROM_HANDLE(vk_private_data_slot, slot, privateDataSlot);
185 if (slot == NULL)
186 return;
187
188 vk_object_base_finish(&slot->base);
189 vk_free2(&device->alloc, pAllocator, slot);
190 }
191
192 static VkResult
get_swapchain_private_data_locked(struct vk_device * device,uint64_t objectHandle,struct vk_private_data_slot * slot,uint64_t ** private_data)193 get_swapchain_private_data_locked(struct vk_device *device,
194 uint64_t objectHandle,
195 struct vk_private_data_slot *slot,
196 uint64_t **private_data)
197 {
198 if (unlikely(device->swapchain_private == NULL)) {
199 /* Even though VkSwapchain/Surface are non-dispatchable objects, we know
200 * a priori that these are actually pointers so we can use
201 * the pointer hash table for them.
202 */
203 device->swapchain_private = _mesa_pointer_hash_table_create(NULL);
204 if (device->swapchain_private == NULL)
205 return VK_ERROR_OUT_OF_HOST_MEMORY;
206 }
207
208 struct hash_entry *entry =
209 _mesa_hash_table_search(device->swapchain_private,
210 (void *)(uintptr_t)objectHandle);
211 if (unlikely(entry == NULL)) {
212 struct util_sparse_array *swapchain_private =
213 ralloc(device->swapchain_private, struct util_sparse_array);
214 util_sparse_array_init(swapchain_private, sizeof(uint64_t), 8);
215
216 entry = _mesa_hash_table_insert(device->swapchain_private,
217 (void *)(uintptr_t)objectHandle,
218 swapchain_private);
219 if (entry == NULL)
220 return VK_ERROR_OUT_OF_HOST_MEMORY;
221 }
222
223 struct util_sparse_array *swapchain_private = entry->data;
224 *private_data = util_sparse_array_get(swapchain_private, slot->index);
225
226 return VK_SUCCESS;
227 }
228
229 static VkResult
vk_object_base_private_data(struct vk_device * device,VkObjectType objectType,uint64_t objectHandle,VkPrivateDataSlot privateDataSlot,uint64_t ** private_data)230 vk_object_base_private_data(struct vk_device *device,
231 VkObjectType objectType,
232 uint64_t objectHandle,
233 VkPrivateDataSlot privateDataSlot,
234 uint64_t **private_data)
235 {
236 VK_FROM_HANDLE(vk_private_data_slot, slot, privateDataSlot);
237
238 /* There is an annoying spec corner here on Android. Because WSI is
239 * implemented in the Vulkan loader which doesn't know about the
240 * VK_EXT_private_data extension, we have to handle VkSwapchainKHR in the
241 * driver as a special case. On future versions of Android where the
242 * loader does understand VK_EXT_private_data, we'll never see a
243 * vkGet/SetPrivateData call on a swapchain because the loader will
244 * handle it.
245 */
246 #if DETECT_OS_ANDROID
247 if (objectType == VK_OBJECT_TYPE_SWAPCHAIN_KHR ||
248 objectType == VK_OBJECT_TYPE_SURFACE_KHR) {
249 #else
250 if (objectType == VK_OBJECT_TYPE_SURFACE_KHR) {
251 #endif
252 mtx_lock(&device->swapchain_private_mtx);
253 VkResult result = get_swapchain_private_data_locked(device, objectHandle,
254 slot, private_data);
255 mtx_unlock(&device->swapchain_private_mtx);
256 return result;
257 }
258
259 struct vk_object_base *obj =
260 vk_object_base_from_u64_handle(objectHandle, objectType);
261 *private_data = util_sparse_array_get(&obj->private_data, slot->index);
262
263 return VK_SUCCESS;
264 }
265
266 VkResult
267 vk_object_base_set_private_data(struct vk_device *device,
268 VkObjectType objectType,
269 uint64_t objectHandle,
270 VkPrivateDataSlot privateDataSlot,
271 uint64_t data)
272 {
273 uint64_t *private_data;
274 VkResult result = vk_object_base_private_data(device,
275 objectType, objectHandle,
276 privateDataSlot,
277 &private_data);
278 if (unlikely(result != VK_SUCCESS))
279 return result;
280
281 *private_data = data;
282 return VK_SUCCESS;
283 }
284
285 void
286 vk_object_base_get_private_data(struct vk_device *device,
287 VkObjectType objectType,
288 uint64_t objectHandle,
289 VkPrivateDataSlot privateDataSlot,
290 uint64_t *pData)
291 {
292 uint64_t *private_data;
293 VkResult result = vk_object_base_private_data(device,
294 objectType, objectHandle,
295 privateDataSlot,
296 &private_data);
297 if (likely(result == VK_SUCCESS)) {
298 *pData = *private_data;
299 } else {
300 *pData = 0;
301 }
302 }
303
304 VKAPI_ATTR VkResult VKAPI_CALL
305 vk_common_CreatePrivateDataSlot(VkDevice _device,
306 const VkPrivateDataSlotCreateInfo *pCreateInfo,
307 const VkAllocationCallbacks *pAllocator,
308 VkPrivateDataSlot *pPrivateDataSlot)
309 {
310 VK_FROM_HANDLE(vk_device, device, _device);
311 return vk_private_data_slot_create(device, pCreateInfo, pAllocator,
312 pPrivateDataSlot);
313 }
314
315 VKAPI_ATTR void VKAPI_CALL
316 vk_common_DestroyPrivateDataSlot(VkDevice _device,
317 VkPrivateDataSlot privateDataSlot,
318 const VkAllocationCallbacks *pAllocator)
319 {
320 VK_FROM_HANDLE(vk_device, device, _device);
321 vk_private_data_slot_destroy(device, privateDataSlot, pAllocator);
322 }
323
324 VKAPI_ATTR VkResult VKAPI_CALL
325 vk_common_SetPrivateData(VkDevice _device,
326 VkObjectType objectType,
327 uint64_t objectHandle,
328 VkPrivateDataSlot privateDataSlot,
329 uint64_t data)
330 {
331 VK_FROM_HANDLE(vk_device, device, _device);
332 return vk_object_base_set_private_data(device,
333 objectType, objectHandle,
334 privateDataSlot, data);
335 }
336
337 VKAPI_ATTR void VKAPI_CALL
338 vk_common_GetPrivateData(VkDevice _device,
339 VkObjectType objectType,
340 uint64_t objectHandle,
341 VkPrivateDataSlot privateDataSlot,
342 uint64_t *pData)
343 {
344 VK_FROM_HANDLE(vk_device, device, _device);
345 vk_object_base_get_private_data(device,
346 objectType, objectHandle,
347 privateDataSlot, pData);
348 }
349
350 const char *
351 vk_object_base_name(struct vk_object_base *obj)
352 {
353 if (obj->object_name)
354 return obj->object_name;
355
356 obj->object_name = vk_asprintf(&obj->device->alloc,
357 VK_SYSTEM_ALLOCATION_SCOPE_DEVICE,
358 "%s(0x%"PRIx64")",
359 vk_ObjectType_to_ObjectName(obj->type),
360 (uint64_t)(uintptr_t)obj);
361
362 return obj->object_name;
363 }
364