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
33void
34vk_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
46void
47vk_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
55void *
56vk_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
71void *
72vk_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
87void *
88vk_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
103void *
104vk_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
119void
120vk_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
128VkResult
129vk_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
149void
150vk_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
163static VkResult
164get_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
201static VkResult
202vk_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
235VkResult
236vk_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
254void
255vk_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
273VKAPI_ATTR VkResult VKAPI_CALL
274vk_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
284VKAPI_ATTR void VKAPI_CALL
285vk_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
293VKAPI_ATTR VkResult VKAPI_CALL
294vk_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
306VKAPI_ATTR void VKAPI_CALL
307vk_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
319const char *
320vk_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