1 /*
2  * Copyright © 2019 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 <string.h>
25 #include <stdlib.h>
26 #include <assert.h>
27 #include <stdio.h>
28 
29 #include <vulkan/vulkan.h>
30 #include <vulkan/vk_layer.h>
31 
32 #include "util/debug.h"
33 #include "util/hash_table.h"
34 #include "util/macros.h"
35 #include "util/simple_mtx.h"
36 
37 #include "vk_dispatch_table.h"
38 #include "vk_enum_to_str.h"
39 #include "vk_util.h"
40 
41 struct instance_data {
42    struct vk_instance_dispatch_table vtable;
43    VkInstance instance;
44 };
45 
46 struct device_data {
47    struct instance_data *instance;
48 
49    PFN_vkSetDeviceLoaderData set_device_loader_data;
50 
51    struct vk_device_dispatch_table vtable;
52    VkPhysicalDevice physical_device;
53    VkDevice device;
54 };
55 
56 static struct hash_table_u64 *vk_object_to_data = NULL;
57 static simple_mtx_t vk_object_to_data_mutex = _SIMPLE_MTX_INITIALIZER_NP;
58 
ensure_vk_object_map(void)59 static inline void ensure_vk_object_map(void)
60 {
61    if (!vk_object_to_data)
62       vk_object_to_data = _mesa_hash_table_u64_create(NULL);
63 }
64 
65 #define HKEY(obj) ((uint64_t)(obj))
66 #define FIND(type, obj) ((type *)find_object_data(HKEY(obj)))
67 
find_object_data(uint64_t obj)68 static void *find_object_data(uint64_t obj)
69 {
70    simple_mtx_lock(&vk_object_to_data_mutex);
71    ensure_vk_object_map();
72    void *data = _mesa_hash_table_u64_search(vk_object_to_data, obj);
73    simple_mtx_unlock(&vk_object_to_data_mutex);
74    return data;
75 }
76 
map_object(uint64_t obj,void * data)77 static void map_object(uint64_t obj, void *data)
78 {
79    simple_mtx_lock(&vk_object_to_data_mutex);
80    ensure_vk_object_map();
81    _mesa_hash_table_u64_insert(vk_object_to_data, obj, data);
82    simple_mtx_unlock(&vk_object_to_data_mutex);
83 }
84 
unmap_object(uint64_t obj)85 static void unmap_object(uint64_t obj)
86 {
87    simple_mtx_lock(&vk_object_to_data_mutex);
88    _mesa_hash_table_u64_remove(vk_object_to_data, obj);
89    simple_mtx_unlock(&vk_object_to_data_mutex);
90 }
91 
92 /**/
93 
94 #define VK_CHECK(expr) \
95    do { \
96       VkResult __result = (expr); \
97       if (__result != VK_SUCCESS) { \
98          fprintf(stderr, "'%s' line %i failed with %s\n", \
99                  #expr, __LINE__, vk_Result_to_str(__result)); \
100       } \
101    } while (0)
102 
103 /**/
104 
override_queue(struct device_data * device_data,VkDevice device,uint32_t queue_family_index,VkQueue queue)105 static void override_queue(struct device_data *device_data,
106                            VkDevice device,
107                            uint32_t queue_family_index,
108                            VkQueue queue)
109 {
110    VkCommandPoolCreateInfo cmd_buffer_pool_info = {
111       .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
112       .queueFamilyIndex = queue_family_index,
113    };
114    VkCommandPool cmd_pool;
115    VK_CHECK(device_data->vtable.CreateCommandPool(device,
116                                                   &cmd_buffer_pool_info,
117                                                   NULL, &cmd_pool));
118 
119 
120    VkCommandBufferAllocateInfo cmd_buffer_info = {
121       .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
122       .commandPool = cmd_pool,
123       .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
124       .commandBufferCount = 1,
125    };
126    VkCommandBuffer cmd_buffer;
127    VK_CHECK(device_data->vtable.AllocateCommandBuffers(device,
128                                                        &cmd_buffer_info,
129                                                        &cmd_buffer));
130    VK_CHECK(device_data->set_device_loader_data(device, cmd_buffer));
131 
132    VkCommandBufferBeginInfo buffer_begin_info = {
133       .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
134    };
135    device_data->vtable.BeginCommandBuffer(cmd_buffer, &buffer_begin_info);
136 
137    VkPerformanceOverrideInfoINTEL override_info = {
138       .sType = VK_STRUCTURE_TYPE_PERFORMANCE_OVERRIDE_INFO_INTEL,
139       .type = VK_PERFORMANCE_OVERRIDE_TYPE_NULL_HARDWARE_INTEL,
140       .enable = VK_TRUE,
141    };
142    device_data->vtable.CmdSetPerformanceOverrideINTEL(cmd_buffer, &override_info);
143 
144    device_data->vtable.EndCommandBuffer(cmd_buffer);
145 
146    VkSubmitInfo submit_info = {
147       .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
148       .commandBufferCount = 1,
149       .pCommandBuffers = &cmd_buffer,
150    };
151    VK_CHECK(device_data->vtable.QueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE));
152 
153    VK_CHECK(device_data->vtable.QueueWaitIdle(queue));
154 
155    device_data->vtable.DestroyCommandPool(device, cmd_pool, NULL);
156 }
157 
device_override_queues(struct device_data * device_data,const VkDeviceCreateInfo * pCreateInfo)158 static void device_override_queues(struct device_data *device_data,
159                                    const VkDeviceCreateInfo *pCreateInfo)
160 {
161    for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++) {
162       for (uint32_t j = 0; j < pCreateInfo->pQueueCreateInfos[i].queueCount; j++) {
163          VkQueue queue;
164          device_data->vtable.GetDeviceQueue(device_data->device,
165                                             pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex,
166                                             j, &queue);
167 
168          VK_CHECK(device_data->set_device_loader_data(device_data->device, queue));
169 
170          override_queue(device_data, device_data->device,
171                         pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex, queue);
172       }
173    }
174 }
175 
get_device_chain_info(const VkDeviceCreateInfo * pCreateInfo,VkLayerFunction func)176 static VkLayerDeviceCreateInfo *get_device_chain_info(const VkDeviceCreateInfo *pCreateInfo,
177                                                       VkLayerFunction func)
178 {
179    vk_foreach_struct(item, pCreateInfo->pNext) {
180       if (item->sType == VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO &&
181           ((VkLayerDeviceCreateInfo *) item)->function == func)
182          return (VkLayerDeviceCreateInfo *)item;
183    }
184    unreachable("device chain info not found");
185    return NULL;
186 }
187 
new_device_data(VkDevice device,struct instance_data * instance)188 static struct device_data *new_device_data(VkDevice device, struct instance_data *instance)
189 {
190    struct device_data *data = calloc(1, sizeof(*data));
191    data->instance = instance;
192    data->device = device;
193    map_object(HKEY(data->device), data);
194    return data;
195 }
196 
destroy_device_data(struct device_data * data)197 static void destroy_device_data(struct device_data *data)
198 {
199    unmap_object(HKEY(data->device));
200    free(data);
201 }
202 
nullhw_CreateDevice(VkPhysicalDevice physicalDevice,const VkDeviceCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkDevice * pDevice)203 static VkResult nullhw_CreateDevice(
204     VkPhysicalDevice                            physicalDevice,
205     const VkDeviceCreateInfo*                   pCreateInfo,
206     const VkAllocationCallbacks*                pAllocator,
207     VkDevice*                                   pDevice)
208 {
209    VkLayerDeviceCreateInfo *chain_info =
210       get_device_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
211 
212    assert(chain_info->u.pLayerInfo);
213    PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
214    PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;
215    PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(NULL, "vkCreateDevice");
216    if (fpCreateDevice == NULL) {
217       return VK_ERROR_INITIALIZATION_FAILED;
218    }
219 
220    // Advance the link info for the next element on the chain
221    chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
222 
223    VkDeviceCreateInfo device_info = *pCreateInfo;
224    const char **extensions = calloc(device_info.enabledExtensionCount + 1, sizeof(*extensions));
225    bool found = false;
226    for (uint32_t i = 0; i < device_info.enabledExtensionCount; i++) {
227       if (!strcmp(device_info.ppEnabledExtensionNames[i], "VK_INTEL_performance_query")) {
228          found = true;
229          break;
230       }
231    }
232    if (!found) {
233       memcpy(extensions, device_info.ppEnabledExtensionNames,
234              sizeof(*extensions) * device_info.enabledExtensionCount);
235       extensions[device_info.enabledExtensionCount++] = "VK_INTEL_performance_query";
236       device_info.ppEnabledExtensionNames = extensions;
237    }
238 
239    VkResult result = fpCreateDevice(physicalDevice, &device_info, pAllocator, pDevice);
240    free(extensions);
241    if (result != VK_SUCCESS) return result;
242 
243    struct instance_data *instance_data = FIND(struct instance_data, physicalDevice);
244    struct device_data *device_data = new_device_data(*pDevice, instance_data);
245    device_data->physical_device = physicalDevice;
246    vk_device_dispatch_table_load(&device_data->vtable, fpGetDeviceProcAddr, *pDevice);
247 
248    VkLayerDeviceCreateInfo *load_data_info =
249       get_device_chain_info(pCreateInfo, VK_LOADER_DATA_CALLBACK);
250    device_data->set_device_loader_data = load_data_info->u.pfnSetDeviceLoaderData;
251 
252    device_override_queues(device_data, pCreateInfo);
253 
254    return result;
255 }
256 
nullhw_DestroyDevice(VkDevice device,const VkAllocationCallbacks * pAllocator)257 static void nullhw_DestroyDevice(
258     VkDevice                                    device,
259     const VkAllocationCallbacks*                pAllocator)
260 {
261    struct device_data *device_data = FIND(struct device_data, device);
262    device_data->vtable.DestroyDevice(device, pAllocator);
263    destroy_device_data(device_data);
264 }
265 
new_instance_data(VkInstance instance)266 static struct instance_data *new_instance_data(VkInstance instance)
267 {
268    struct instance_data *data = calloc(1, sizeof(*data));
269    data->instance = instance;
270    map_object(HKEY(data->instance), data);
271    return data;
272 }
273 
destroy_instance_data(struct instance_data * data)274 static void destroy_instance_data(struct instance_data *data)
275 {
276    unmap_object(HKEY(data->instance));
277    free(data);
278 }
279 
get_instance_chain_info(const VkInstanceCreateInfo * pCreateInfo,VkLayerFunction func)280 static VkLayerInstanceCreateInfo *get_instance_chain_info(const VkInstanceCreateInfo *pCreateInfo,
281                                                           VkLayerFunction func)
282 {
283    vk_foreach_struct(item, pCreateInfo->pNext) {
284       if (item->sType == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO &&
285           ((VkLayerInstanceCreateInfo *) item)->function == func)
286          return (VkLayerInstanceCreateInfo *) item;
287    }
288    unreachable("instance chain info not found");
289    return NULL;
290 }
291 
nullhw_CreateInstance(const VkInstanceCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkInstance * pInstance)292 static VkResult nullhw_CreateInstance(
293     const VkInstanceCreateInfo*                 pCreateInfo,
294     const VkAllocationCallbacks*                pAllocator,
295     VkInstance*                                 pInstance)
296 {
297    VkLayerInstanceCreateInfo *chain_info =
298       get_instance_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
299 
300    assert(chain_info->u.pLayerInfo);
301    PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr =
302       chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
303    PFN_vkCreateInstance fpCreateInstance =
304       (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance");
305    if (fpCreateInstance == NULL) {
306       return VK_ERROR_INITIALIZATION_FAILED;
307    }
308 
309    // Advance the link info for the next element on the chain
310    chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
311 
312    VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
313    if (result != VK_SUCCESS) return result;
314 
315    struct instance_data *instance_data = new_instance_data(*pInstance);
316    vk_instance_dispatch_table_load(&instance_data->vtable,
317                                    fpGetInstanceProcAddr,
318                                    instance_data->instance);
319 
320    return result;
321 }
322 
nullhw_DestroyInstance(VkInstance instance,const VkAllocationCallbacks * pAllocator)323 static void nullhw_DestroyInstance(
324     VkInstance                                  instance,
325     const VkAllocationCallbacks*                pAllocator)
326 {
327    struct instance_data *instance_data = FIND(struct instance_data, instance);
328    instance_data->vtable.DestroyInstance(instance, pAllocator);
329    destroy_instance_data(instance_data);
330 }
331 
332 static const struct {
333    const char *name;
334    void *ptr;
335 } name_to_funcptr_map[] = {
336    { "vkGetDeviceProcAddr", (void *) vkGetDeviceProcAddr },
337 #define ADD_HOOK(fn) { "vk" # fn, (void *) nullhw_ ## fn }
338    ADD_HOOK(CreateInstance),
339    ADD_HOOK(DestroyInstance),
340    ADD_HOOK(CreateDevice),
341    ADD_HOOK(DestroyDevice),
342 };
343 
find_ptr(const char * name)344 static void *find_ptr(const char *name)
345 {
346    for (uint32_t i = 0; i < ARRAY_SIZE(name_to_funcptr_map); i++) {
347       if (strcmp(name, name_to_funcptr_map[i].name) == 0)
348          return name_to_funcptr_map[i].ptr;
349    }
350 
351    return NULL;
352 }
353 
vkGetDeviceProcAddr(VkDevice dev,const char * funcName)354 VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev,
355                                                                              const char *funcName)
356 {
357    void *ptr = find_ptr(funcName);
358    if (ptr) return (PFN_vkVoidFunction)(ptr);
359 
360    if (dev == NULL) return NULL;
361 
362    struct device_data *device_data = FIND(struct device_data, dev);
363    if (device_data->vtable.GetDeviceProcAddr == NULL) return NULL;
364    return device_data->vtable.GetDeviceProcAddr(dev, funcName);
365 }
366 
vkGetInstanceProcAddr(VkInstance instance,const char * funcName)367 VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance,
368                                                                                const char *funcName)
369 {
370    void *ptr = find_ptr(funcName);
371    if (ptr) return (PFN_vkVoidFunction) ptr;
372 
373    struct instance_data *instance_data = FIND(struct instance_data, instance);
374    if (instance_data->vtable.GetInstanceProcAddr == NULL) return NULL;
375    return instance_data->vtable.GetInstanceProcAddr(instance, funcName);
376 }
377