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