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
vk_object_base_init(UNUSED struct vk_device * device,struct vk_object_base * base,UNUSED VkObjectType obj_type)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
vk_object_base_finish(struct vk_object_base * base)41 vk_object_base_finish(struct vk_object_base *base)
42 {
43    util_sparse_array_finish(&base->private_data);
44 }
45 
46 void
vk_device_init(struct vk_device * device,UNUSED const VkDeviceCreateInfo * pCreateInfo,const VkAllocationCallbacks * instance_alloc,const VkAllocationCallbacks * device_alloc)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
vk_device_finish(UNUSED struct vk_device * device)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 *
vk_object_alloc(struct vk_device * device,const VkAllocationCallbacks * alloc,size_t size,VkObjectType obj_type)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 *
vk_object_zalloc(struct vk_device * device,const VkAllocationCallbacks * alloc,size_t size,VkObjectType obj_type)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
vk_object_free(struct vk_device * device,const VkAllocationCallbacks * alloc,void * data)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
vk_private_data_slot_create(struct vk_device * device,const VkPrivateDataSlotCreateInfoEXT * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkPrivateDataSlotEXT * pPrivateDataSlot)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
vk_private_data_slot_destroy(struct vk_device * device,VkPrivateDataSlotEXT privateDataSlot,const VkAllocationCallbacks * pAllocator)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
get_swapchain_private_data_locked(struct vk_device * device,uint64_t objectHandle,struct vk_private_data_slot * slot,uint64_t ** private_data)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
vk_object_base_private_data(struct vk_device * device,VkObjectType objectType,uint64_t objectHandle,VkPrivateDataSlotEXT privateDataSlot,uint64_t ** private_data)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
vk_object_base_set_private_data(struct vk_device * device,VkObjectType objectType,uint64_t objectHandle,VkPrivateDataSlotEXT privateDataSlot,uint64_t data)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
vk_object_base_get_private_data(struct vk_device * device,VkObjectType objectType,uint64_t objectHandle,VkPrivateDataSlotEXT privateDataSlot,uint64_t * pData)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 }
265