17ec681f3Smrg/* 27ec681f3Smrg * Copyright © 2019 Intel Corporation 37ec681f3Smrg * 47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a 57ec681f3Smrg * copy of this software and associated documentation files (the "Software"), 67ec681f3Smrg * to deal in the Software without restriction, including without limitation 77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the 97ec681f3Smrg * Software is furnished to do so, subject to the following conditions: 107ec681f3Smrg * 117ec681f3Smrg * The above copyright notice and this permission notice (including the next 127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the 137ec681f3Smrg * Software. 147ec681f3Smrg * 157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 187ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 197ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 207ec681f3Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 217ec681f3Smrg * IN THE SOFTWARE. 227ec681f3Smrg */ 237ec681f3Smrg 247ec681f3Smrg#include <string.h> 257ec681f3Smrg#include <stdlib.h> 267ec681f3Smrg#include <assert.h> 277ec681f3Smrg#include <stdio.h> 287ec681f3Smrg 297ec681f3Smrg#include <vulkan/vulkan.h> 307ec681f3Smrg#include <vulkan/vk_layer.h> 317ec681f3Smrg 327ec681f3Smrg#include "util/debug.h" 337ec681f3Smrg#include "util/hash_table.h" 347ec681f3Smrg#include "util/macros.h" 357ec681f3Smrg#include "util/simple_mtx.h" 367ec681f3Smrg 377ec681f3Smrg#include "vk_dispatch_table.h" 387ec681f3Smrg#include "vk_enum_to_str.h" 397ec681f3Smrg#include "vk_util.h" 407ec681f3Smrg 417ec681f3Smrgstruct instance_data { 427ec681f3Smrg struct vk_instance_dispatch_table vtable; 437ec681f3Smrg VkInstance instance; 447ec681f3Smrg}; 457ec681f3Smrg 467ec681f3Smrgstruct device_data { 477ec681f3Smrg struct instance_data *instance; 487ec681f3Smrg 497ec681f3Smrg PFN_vkSetDeviceLoaderData set_device_loader_data; 507ec681f3Smrg 517ec681f3Smrg struct vk_device_dispatch_table vtable; 527ec681f3Smrg VkPhysicalDevice physical_device; 537ec681f3Smrg VkDevice device; 547ec681f3Smrg}; 557ec681f3Smrg 567ec681f3Smrgstatic struct hash_table_u64 *vk_object_to_data = NULL; 577ec681f3Smrgstatic simple_mtx_t vk_object_to_data_mutex = _SIMPLE_MTX_INITIALIZER_NP; 587ec681f3Smrg 597ec681f3Smrgstatic inline void ensure_vk_object_map(void) 607ec681f3Smrg{ 617ec681f3Smrg if (!vk_object_to_data) 627ec681f3Smrg vk_object_to_data = _mesa_hash_table_u64_create(NULL); 637ec681f3Smrg} 647ec681f3Smrg 657ec681f3Smrg#define HKEY(obj) ((uint64_t)(obj)) 667ec681f3Smrg#define FIND(type, obj) ((type *)find_object_data(HKEY(obj))) 677ec681f3Smrg 687ec681f3Smrgstatic void *find_object_data(uint64_t obj) 697ec681f3Smrg{ 707ec681f3Smrg simple_mtx_lock(&vk_object_to_data_mutex); 717ec681f3Smrg ensure_vk_object_map(); 727ec681f3Smrg void *data = _mesa_hash_table_u64_search(vk_object_to_data, obj); 737ec681f3Smrg simple_mtx_unlock(&vk_object_to_data_mutex); 747ec681f3Smrg return data; 757ec681f3Smrg} 767ec681f3Smrg 777ec681f3Smrgstatic void map_object(uint64_t obj, void *data) 787ec681f3Smrg{ 797ec681f3Smrg simple_mtx_lock(&vk_object_to_data_mutex); 807ec681f3Smrg ensure_vk_object_map(); 817ec681f3Smrg _mesa_hash_table_u64_insert(vk_object_to_data, obj, data); 827ec681f3Smrg simple_mtx_unlock(&vk_object_to_data_mutex); 837ec681f3Smrg} 847ec681f3Smrg 857ec681f3Smrgstatic void unmap_object(uint64_t obj) 867ec681f3Smrg{ 877ec681f3Smrg simple_mtx_lock(&vk_object_to_data_mutex); 887ec681f3Smrg _mesa_hash_table_u64_remove(vk_object_to_data, obj); 897ec681f3Smrg simple_mtx_unlock(&vk_object_to_data_mutex); 907ec681f3Smrg} 917ec681f3Smrg 927ec681f3Smrg/**/ 937ec681f3Smrg 947ec681f3Smrg#define VK_CHECK(expr) \ 957ec681f3Smrg do { \ 967ec681f3Smrg VkResult __result = (expr); \ 977ec681f3Smrg if (__result != VK_SUCCESS) { \ 987ec681f3Smrg fprintf(stderr, "'%s' line %i failed with %s\n", \ 997ec681f3Smrg #expr, __LINE__, vk_Result_to_str(__result)); \ 1007ec681f3Smrg } \ 1017ec681f3Smrg } while (0) 1027ec681f3Smrg 1037ec681f3Smrg/**/ 1047ec681f3Smrg 1057ec681f3Smrgstatic void override_queue(struct device_data *device_data, 1067ec681f3Smrg VkDevice device, 1077ec681f3Smrg uint32_t queue_family_index, 1087ec681f3Smrg VkQueue queue) 1097ec681f3Smrg{ 1107ec681f3Smrg VkCommandPoolCreateInfo cmd_buffer_pool_info = { 1117ec681f3Smrg .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, 1127ec681f3Smrg .queueFamilyIndex = queue_family_index, 1137ec681f3Smrg }; 1147ec681f3Smrg VkCommandPool cmd_pool; 1157ec681f3Smrg VK_CHECK(device_data->vtable.CreateCommandPool(device, 1167ec681f3Smrg &cmd_buffer_pool_info, 1177ec681f3Smrg NULL, &cmd_pool)); 1187ec681f3Smrg 1197ec681f3Smrg 1207ec681f3Smrg VkCommandBufferAllocateInfo cmd_buffer_info = { 1217ec681f3Smrg .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, 1227ec681f3Smrg .commandPool = cmd_pool, 1237ec681f3Smrg .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1247ec681f3Smrg .commandBufferCount = 1, 1257ec681f3Smrg }; 1267ec681f3Smrg VkCommandBuffer cmd_buffer; 1277ec681f3Smrg VK_CHECK(device_data->vtable.AllocateCommandBuffers(device, 1287ec681f3Smrg &cmd_buffer_info, 1297ec681f3Smrg &cmd_buffer)); 1307ec681f3Smrg VK_CHECK(device_data->set_device_loader_data(device, cmd_buffer)); 1317ec681f3Smrg 1327ec681f3Smrg VkCommandBufferBeginInfo buffer_begin_info = { 1337ec681f3Smrg .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 1347ec681f3Smrg }; 1357ec681f3Smrg device_data->vtable.BeginCommandBuffer(cmd_buffer, &buffer_begin_info); 1367ec681f3Smrg 1377ec681f3Smrg VkPerformanceOverrideInfoINTEL override_info = { 1387ec681f3Smrg .sType = VK_STRUCTURE_TYPE_PERFORMANCE_OVERRIDE_INFO_INTEL, 1397ec681f3Smrg .type = VK_PERFORMANCE_OVERRIDE_TYPE_NULL_HARDWARE_INTEL, 1407ec681f3Smrg .enable = VK_TRUE, 1417ec681f3Smrg }; 1427ec681f3Smrg device_data->vtable.CmdSetPerformanceOverrideINTEL(cmd_buffer, &override_info); 1437ec681f3Smrg 1447ec681f3Smrg device_data->vtable.EndCommandBuffer(cmd_buffer); 1457ec681f3Smrg 1467ec681f3Smrg VkSubmitInfo submit_info = { 1477ec681f3Smrg .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, 1487ec681f3Smrg .commandBufferCount = 1, 1497ec681f3Smrg .pCommandBuffers = &cmd_buffer, 1507ec681f3Smrg }; 1517ec681f3Smrg VK_CHECK(device_data->vtable.QueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE)); 1527ec681f3Smrg 1537ec681f3Smrg VK_CHECK(device_data->vtable.QueueWaitIdle(queue)); 1547ec681f3Smrg 1557ec681f3Smrg device_data->vtable.DestroyCommandPool(device, cmd_pool, NULL); 1567ec681f3Smrg} 1577ec681f3Smrg 1587ec681f3Smrgstatic void device_override_queues(struct device_data *device_data, 1597ec681f3Smrg const VkDeviceCreateInfo *pCreateInfo) 1607ec681f3Smrg{ 1617ec681f3Smrg for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++) { 1627ec681f3Smrg for (uint32_t j = 0; j < pCreateInfo->pQueueCreateInfos[i].queueCount; j++) { 1637ec681f3Smrg VkQueue queue; 1647ec681f3Smrg device_data->vtable.GetDeviceQueue(device_data->device, 1657ec681f3Smrg pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex, 1667ec681f3Smrg j, &queue); 1677ec681f3Smrg 1687ec681f3Smrg VK_CHECK(device_data->set_device_loader_data(device_data->device, queue)); 1697ec681f3Smrg 1707ec681f3Smrg override_queue(device_data, device_data->device, 1717ec681f3Smrg pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex, queue); 1727ec681f3Smrg } 1737ec681f3Smrg } 1747ec681f3Smrg} 1757ec681f3Smrg 1767ec681f3Smrgstatic VkLayerDeviceCreateInfo *get_device_chain_info(const VkDeviceCreateInfo *pCreateInfo, 1777ec681f3Smrg VkLayerFunction func) 1787ec681f3Smrg{ 1797ec681f3Smrg vk_foreach_struct(item, pCreateInfo->pNext) { 1807ec681f3Smrg if (item->sType == VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO && 1817ec681f3Smrg ((VkLayerDeviceCreateInfo *) item)->function == func) 1827ec681f3Smrg return (VkLayerDeviceCreateInfo *)item; 1837ec681f3Smrg } 1847ec681f3Smrg unreachable("device chain info not found"); 1857ec681f3Smrg return NULL; 1867ec681f3Smrg} 1877ec681f3Smrg 1887ec681f3Smrgstatic struct device_data *new_device_data(VkDevice device, struct instance_data *instance) 1897ec681f3Smrg{ 1907ec681f3Smrg struct device_data *data = calloc(1, sizeof(*data)); 1917ec681f3Smrg data->instance = instance; 1927ec681f3Smrg data->device = device; 1937ec681f3Smrg map_object(HKEY(data->device), data); 1947ec681f3Smrg return data; 1957ec681f3Smrg} 1967ec681f3Smrg 1977ec681f3Smrgstatic void destroy_device_data(struct device_data *data) 1987ec681f3Smrg{ 1997ec681f3Smrg unmap_object(HKEY(data->device)); 2007ec681f3Smrg free(data); 2017ec681f3Smrg} 2027ec681f3Smrg 2037ec681f3Smrgstatic VkResult nullhw_CreateDevice( 2047ec681f3Smrg VkPhysicalDevice physicalDevice, 2057ec681f3Smrg const VkDeviceCreateInfo* pCreateInfo, 2067ec681f3Smrg const VkAllocationCallbacks* pAllocator, 2077ec681f3Smrg VkDevice* pDevice) 2087ec681f3Smrg{ 2097ec681f3Smrg VkLayerDeviceCreateInfo *chain_info = 2107ec681f3Smrg get_device_chain_info(pCreateInfo, VK_LAYER_LINK_INFO); 2117ec681f3Smrg 2127ec681f3Smrg assert(chain_info->u.pLayerInfo); 2137ec681f3Smrg PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr; 2147ec681f3Smrg PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr; 2157ec681f3Smrg PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(NULL, "vkCreateDevice"); 2167ec681f3Smrg if (fpCreateDevice == NULL) { 2177ec681f3Smrg return VK_ERROR_INITIALIZATION_FAILED; 2187ec681f3Smrg } 2197ec681f3Smrg 2207ec681f3Smrg // Advance the link info for the next element on the chain 2217ec681f3Smrg chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext; 2227ec681f3Smrg 2237ec681f3Smrg VkDeviceCreateInfo device_info = *pCreateInfo; 2247ec681f3Smrg const char **extensions = calloc(device_info.enabledExtensionCount + 1, sizeof(*extensions)); 2257ec681f3Smrg bool found = false; 2267ec681f3Smrg for (uint32_t i = 0; i < device_info.enabledExtensionCount; i++) { 2277ec681f3Smrg if (!strcmp(device_info.ppEnabledExtensionNames[i], "VK_INTEL_performance_query")) { 2287ec681f3Smrg found = true; 2297ec681f3Smrg break; 2307ec681f3Smrg } 2317ec681f3Smrg } 2327ec681f3Smrg if (!found) { 2337ec681f3Smrg memcpy(extensions, device_info.ppEnabledExtensionNames, 2347ec681f3Smrg sizeof(*extensions) * device_info.enabledExtensionCount); 2357ec681f3Smrg extensions[device_info.enabledExtensionCount++] = "VK_INTEL_performance_query"; 2367ec681f3Smrg device_info.ppEnabledExtensionNames = extensions; 2377ec681f3Smrg } 2387ec681f3Smrg 2397ec681f3Smrg VkResult result = fpCreateDevice(physicalDevice, &device_info, pAllocator, pDevice); 2407ec681f3Smrg free(extensions); 2417ec681f3Smrg if (result != VK_SUCCESS) return result; 2427ec681f3Smrg 2437ec681f3Smrg struct instance_data *instance_data = FIND(struct instance_data, physicalDevice); 2447ec681f3Smrg struct device_data *device_data = new_device_data(*pDevice, instance_data); 2457ec681f3Smrg device_data->physical_device = physicalDevice; 2467ec681f3Smrg vk_device_dispatch_table_load(&device_data->vtable, fpGetDeviceProcAddr, *pDevice); 2477ec681f3Smrg 2487ec681f3Smrg VkLayerDeviceCreateInfo *load_data_info = 2497ec681f3Smrg get_device_chain_info(pCreateInfo, VK_LOADER_DATA_CALLBACK); 2507ec681f3Smrg device_data->set_device_loader_data = load_data_info->u.pfnSetDeviceLoaderData; 2517ec681f3Smrg 2527ec681f3Smrg device_override_queues(device_data, pCreateInfo); 2537ec681f3Smrg 2547ec681f3Smrg return result; 2557ec681f3Smrg} 2567ec681f3Smrg 2577ec681f3Smrgstatic void nullhw_DestroyDevice( 2587ec681f3Smrg VkDevice device, 2597ec681f3Smrg const VkAllocationCallbacks* pAllocator) 2607ec681f3Smrg{ 2617ec681f3Smrg struct device_data *device_data = FIND(struct device_data, device); 2627ec681f3Smrg device_data->vtable.DestroyDevice(device, pAllocator); 2637ec681f3Smrg destroy_device_data(device_data); 2647ec681f3Smrg} 2657ec681f3Smrg 2667ec681f3Smrgstatic struct instance_data *new_instance_data(VkInstance instance) 2677ec681f3Smrg{ 2687ec681f3Smrg struct instance_data *data = calloc(1, sizeof(*data)); 2697ec681f3Smrg data->instance = instance; 2707ec681f3Smrg map_object(HKEY(data->instance), data); 2717ec681f3Smrg return data; 2727ec681f3Smrg} 2737ec681f3Smrg 2747ec681f3Smrgstatic void destroy_instance_data(struct instance_data *data) 2757ec681f3Smrg{ 2767ec681f3Smrg unmap_object(HKEY(data->instance)); 2777ec681f3Smrg free(data); 2787ec681f3Smrg} 2797ec681f3Smrg 2807ec681f3Smrgstatic VkLayerInstanceCreateInfo *get_instance_chain_info(const VkInstanceCreateInfo *pCreateInfo, 2817ec681f3Smrg VkLayerFunction func) 2827ec681f3Smrg{ 2837ec681f3Smrg vk_foreach_struct(item, pCreateInfo->pNext) { 2847ec681f3Smrg if (item->sType == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO && 2857ec681f3Smrg ((VkLayerInstanceCreateInfo *) item)->function == func) 2867ec681f3Smrg return (VkLayerInstanceCreateInfo *) item; 2877ec681f3Smrg } 2887ec681f3Smrg unreachable("instance chain info not found"); 2897ec681f3Smrg return NULL; 2907ec681f3Smrg} 2917ec681f3Smrg 2927ec681f3Smrgstatic VkResult nullhw_CreateInstance( 2937ec681f3Smrg const VkInstanceCreateInfo* pCreateInfo, 2947ec681f3Smrg const VkAllocationCallbacks* pAllocator, 2957ec681f3Smrg VkInstance* pInstance) 2967ec681f3Smrg{ 2977ec681f3Smrg VkLayerInstanceCreateInfo *chain_info = 2987ec681f3Smrg get_instance_chain_info(pCreateInfo, VK_LAYER_LINK_INFO); 2997ec681f3Smrg 3007ec681f3Smrg assert(chain_info->u.pLayerInfo); 3017ec681f3Smrg PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = 3027ec681f3Smrg chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr; 3037ec681f3Smrg PFN_vkCreateInstance fpCreateInstance = 3047ec681f3Smrg (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance"); 3057ec681f3Smrg if (fpCreateInstance == NULL) { 3067ec681f3Smrg return VK_ERROR_INITIALIZATION_FAILED; 3077ec681f3Smrg } 3087ec681f3Smrg 3097ec681f3Smrg // Advance the link info for the next element on the chain 3107ec681f3Smrg chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext; 3117ec681f3Smrg 3127ec681f3Smrg VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance); 3137ec681f3Smrg if (result != VK_SUCCESS) return result; 3147ec681f3Smrg 3157ec681f3Smrg struct instance_data *instance_data = new_instance_data(*pInstance); 3167ec681f3Smrg vk_instance_dispatch_table_load(&instance_data->vtable, 3177ec681f3Smrg fpGetInstanceProcAddr, 3187ec681f3Smrg instance_data->instance); 3197ec681f3Smrg 3207ec681f3Smrg return result; 3217ec681f3Smrg} 3227ec681f3Smrg 3237ec681f3Smrgstatic void nullhw_DestroyInstance( 3247ec681f3Smrg VkInstance instance, 3257ec681f3Smrg const VkAllocationCallbacks* pAllocator) 3267ec681f3Smrg{ 3277ec681f3Smrg struct instance_data *instance_data = FIND(struct instance_data, instance); 3287ec681f3Smrg instance_data->vtable.DestroyInstance(instance, pAllocator); 3297ec681f3Smrg destroy_instance_data(instance_data); 3307ec681f3Smrg} 3317ec681f3Smrg 3327ec681f3Smrgstatic const struct { 3337ec681f3Smrg const char *name; 3347ec681f3Smrg void *ptr; 3357ec681f3Smrg} name_to_funcptr_map[] = { 3367ec681f3Smrg { "vkGetDeviceProcAddr", (void *) vkGetDeviceProcAddr }, 3377ec681f3Smrg#define ADD_HOOK(fn) { "vk" # fn, (void *) nullhw_ ## fn } 3387ec681f3Smrg ADD_HOOK(CreateInstance), 3397ec681f3Smrg ADD_HOOK(DestroyInstance), 3407ec681f3Smrg ADD_HOOK(CreateDevice), 3417ec681f3Smrg ADD_HOOK(DestroyDevice), 3427ec681f3Smrg}; 3437ec681f3Smrg 3447ec681f3Smrgstatic void *find_ptr(const char *name) 3457ec681f3Smrg{ 3467ec681f3Smrg for (uint32_t i = 0; i < ARRAY_SIZE(name_to_funcptr_map); i++) { 3477ec681f3Smrg if (strcmp(name, name_to_funcptr_map[i].name) == 0) 3487ec681f3Smrg return name_to_funcptr_map[i].ptr; 3497ec681f3Smrg } 3507ec681f3Smrg 3517ec681f3Smrg return NULL; 3527ec681f3Smrg} 3537ec681f3Smrg 3547ec681f3SmrgVK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev, 3557ec681f3Smrg const char *funcName) 3567ec681f3Smrg{ 3577ec681f3Smrg void *ptr = find_ptr(funcName); 3587ec681f3Smrg if (ptr) return (PFN_vkVoidFunction)(ptr); 3597ec681f3Smrg 3607ec681f3Smrg if (dev == NULL) return NULL; 3617ec681f3Smrg 3627ec681f3Smrg struct device_data *device_data = FIND(struct device_data, dev); 3637ec681f3Smrg if (device_data->vtable.GetDeviceProcAddr == NULL) return NULL; 3647ec681f3Smrg return device_data->vtable.GetDeviceProcAddr(dev, funcName); 3657ec681f3Smrg} 3667ec681f3Smrg 3677ec681f3SmrgVK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, 3687ec681f3Smrg const char *funcName) 3697ec681f3Smrg{ 3707ec681f3Smrg void *ptr = find_ptr(funcName); 3717ec681f3Smrg if (ptr) return (PFN_vkVoidFunction) ptr; 3727ec681f3Smrg 3737ec681f3Smrg struct instance_data *instance_data = FIND(struct instance_data, instance); 3747ec681f3Smrg if (instance_data->vtable.GetInstanceProcAddr == NULL) return NULL; 3757ec681f3Smrg return instance_data->vtable.GetInstanceProcAddr(instance, funcName); 3767ec681f3Smrg} 377