Path: blob/21.2-virgl/src/intel/nullhw-layer/intel_nullhw.c
4547 views
/*1* Copyright © 2019 Intel Corporation2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING19* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS20* IN THE SOFTWARE.21*/2223#include <string.h>24#include <stdlib.h>25#include <assert.h>26#include <stdio.h>2728#include <vulkan/vulkan.h>29#include <vulkan/vk_layer.h>3031#include "util/debug.h"32#include "util/hash_table.h"33#include "util/macros.h"34#include "util/simple_mtx.h"3536#include "vk_dispatch_table.h"37#include "vk_enum_to_str.h"38#include "vk_util.h"3940struct instance_data {41struct vk_instance_dispatch_table vtable;42VkInstance instance;43};4445struct device_data {46struct instance_data *instance;4748PFN_vkSetDeviceLoaderData set_device_loader_data;4950struct vk_device_dispatch_table vtable;51VkPhysicalDevice physical_device;52VkDevice device;53};5455static struct hash_table_u64 *vk_object_to_data = NULL;56static simple_mtx_t vk_object_to_data_mutex = _SIMPLE_MTX_INITIALIZER_NP;5758static inline void ensure_vk_object_map(void)59{60if (!vk_object_to_data)61vk_object_to_data = _mesa_hash_table_u64_create(NULL);62}6364#define HKEY(obj) ((uint64_t)(obj))65#define FIND(type, obj) ((type *)find_object_data(HKEY(obj)))6667static void *find_object_data(uint64_t obj)68{69simple_mtx_lock(&vk_object_to_data_mutex);70ensure_vk_object_map();71void *data = _mesa_hash_table_u64_search(vk_object_to_data, obj);72simple_mtx_unlock(&vk_object_to_data_mutex);73return data;74}7576static void map_object(uint64_t obj, void *data)77{78simple_mtx_lock(&vk_object_to_data_mutex);79ensure_vk_object_map();80_mesa_hash_table_u64_insert(vk_object_to_data, obj, data);81simple_mtx_unlock(&vk_object_to_data_mutex);82}8384static void unmap_object(uint64_t obj)85{86simple_mtx_lock(&vk_object_to_data_mutex);87_mesa_hash_table_u64_remove(vk_object_to_data, obj);88simple_mtx_unlock(&vk_object_to_data_mutex);89}9091/**/9293#define VK_CHECK(expr) \94do { \95VkResult __result = (expr); \96if (__result != VK_SUCCESS) { \97fprintf(stderr, "'%s' line %i failed with %s\n", \98#expr, __LINE__, vk_Result_to_str(__result)); \99} \100} while (0)101102/**/103104static void override_queue(struct device_data *device_data,105VkDevice device,106uint32_t queue_family_index,107VkQueue queue)108{109VkCommandPoolCreateInfo cmd_buffer_pool_info = {110.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,111.queueFamilyIndex = queue_family_index,112};113VkCommandPool cmd_pool;114VK_CHECK(device_data->vtable.CreateCommandPool(device,115&cmd_buffer_pool_info,116NULL, &cmd_pool));117118119VkCommandBufferAllocateInfo cmd_buffer_info = {120.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,121.commandPool = cmd_pool,122.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,123.commandBufferCount = 1,124};125VkCommandBuffer cmd_buffer;126VK_CHECK(device_data->vtable.AllocateCommandBuffers(device,127&cmd_buffer_info,128&cmd_buffer));129VK_CHECK(device_data->set_device_loader_data(device, cmd_buffer));130131VkCommandBufferBeginInfo buffer_begin_info = {132.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,133};134device_data->vtable.BeginCommandBuffer(cmd_buffer, &buffer_begin_info);135136VkPerformanceOverrideInfoINTEL override_info = {137.sType = VK_STRUCTURE_TYPE_PERFORMANCE_OVERRIDE_INFO_INTEL,138.type = VK_PERFORMANCE_OVERRIDE_TYPE_NULL_HARDWARE_INTEL,139.enable = VK_TRUE,140};141device_data->vtable.CmdSetPerformanceOverrideINTEL(cmd_buffer, &override_info);142143device_data->vtable.EndCommandBuffer(cmd_buffer);144145VkSubmitInfo submit_info = {146.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,147.commandBufferCount = 1,148.pCommandBuffers = &cmd_buffer,149};150VK_CHECK(device_data->vtable.QueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE));151152VK_CHECK(device_data->vtable.QueueWaitIdle(queue));153154device_data->vtable.DestroyCommandPool(device, cmd_pool, NULL);155}156157static void device_override_queues(struct device_data *device_data,158const VkDeviceCreateInfo *pCreateInfo)159{160for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++) {161for (uint32_t j = 0; j < pCreateInfo->pQueueCreateInfos[i].queueCount; j++) {162VkQueue queue;163device_data->vtable.GetDeviceQueue(device_data->device,164pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex,165j, &queue);166167VK_CHECK(device_data->set_device_loader_data(device_data->device, queue));168169override_queue(device_data, device_data->device,170pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex, queue);171}172}173}174175static VkLayerDeviceCreateInfo *get_device_chain_info(const VkDeviceCreateInfo *pCreateInfo,176VkLayerFunction func)177{178vk_foreach_struct(item, pCreateInfo->pNext) {179if (item->sType == VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO &&180((VkLayerDeviceCreateInfo *) item)->function == func)181return (VkLayerDeviceCreateInfo *)item;182}183unreachable("device chain info not found");184return NULL;185}186187static struct device_data *new_device_data(VkDevice device, struct instance_data *instance)188{189struct device_data *data = calloc(1, sizeof(*data));190data->instance = instance;191data->device = device;192map_object(HKEY(data->device), data);193return data;194}195196static void destroy_device_data(struct device_data *data)197{198unmap_object(HKEY(data->device));199free(data);200}201202static VkResult nullhw_CreateDevice(203VkPhysicalDevice physicalDevice,204const VkDeviceCreateInfo* pCreateInfo,205const VkAllocationCallbacks* pAllocator,206VkDevice* pDevice)207{208VkLayerDeviceCreateInfo *chain_info =209get_device_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);210211assert(chain_info->u.pLayerInfo);212PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;213PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;214PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(NULL, "vkCreateDevice");215if (fpCreateDevice == NULL) {216return VK_ERROR_INITIALIZATION_FAILED;217}218219// Advance the link info for the next element on the chain220chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;221222VkDeviceCreateInfo device_info = *pCreateInfo;223const char **extensions = calloc(device_info.enabledExtensionCount + 1, sizeof(*extensions));224bool found = false;225for (uint32_t i = 0; i < device_info.enabledExtensionCount; i++) {226if (!strcmp(device_info.ppEnabledExtensionNames[i], "VK_INTEL_performance_query")) {227found = true;228break;229}230}231if (!found) {232memcpy(extensions, device_info.ppEnabledExtensionNames,233sizeof(*extensions) * device_info.enabledExtensionCount);234extensions[device_info.enabledExtensionCount++] = "VK_INTEL_performance_query";235device_info.ppEnabledExtensionNames = extensions;236}237238VkResult result = fpCreateDevice(physicalDevice, &device_info, pAllocator, pDevice);239free(extensions);240if (result != VK_SUCCESS) return result;241242struct instance_data *instance_data = FIND(struct instance_data, physicalDevice);243struct device_data *device_data = new_device_data(*pDevice, instance_data);244device_data->physical_device = physicalDevice;245vk_device_dispatch_table_load(&device_data->vtable, fpGetDeviceProcAddr, *pDevice);246247VkLayerDeviceCreateInfo *load_data_info =248get_device_chain_info(pCreateInfo, VK_LOADER_DATA_CALLBACK);249device_data->set_device_loader_data = load_data_info->u.pfnSetDeviceLoaderData;250251device_override_queues(device_data, pCreateInfo);252253return result;254}255256static void nullhw_DestroyDevice(257VkDevice device,258const VkAllocationCallbacks* pAllocator)259{260struct device_data *device_data = FIND(struct device_data, device);261device_data->vtable.DestroyDevice(device, pAllocator);262destroy_device_data(device_data);263}264265static struct instance_data *new_instance_data(VkInstance instance)266{267struct instance_data *data = calloc(1, sizeof(*data));268data->instance = instance;269map_object(HKEY(data->instance), data);270return data;271}272273static void destroy_instance_data(struct instance_data *data)274{275unmap_object(HKEY(data->instance));276free(data);277}278279static VkLayerInstanceCreateInfo *get_instance_chain_info(const VkInstanceCreateInfo *pCreateInfo,280VkLayerFunction func)281{282vk_foreach_struct(item, pCreateInfo->pNext) {283if (item->sType == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO &&284((VkLayerInstanceCreateInfo *) item)->function == func)285return (VkLayerInstanceCreateInfo *) item;286}287unreachable("instance chain info not found");288return NULL;289}290291static VkResult nullhw_CreateInstance(292const VkInstanceCreateInfo* pCreateInfo,293const VkAllocationCallbacks* pAllocator,294VkInstance* pInstance)295{296VkLayerInstanceCreateInfo *chain_info =297get_instance_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);298299assert(chain_info->u.pLayerInfo);300PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr =301chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;302PFN_vkCreateInstance fpCreateInstance =303(PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance");304if (fpCreateInstance == NULL) {305return VK_ERROR_INITIALIZATION_FAILED;306}307308// Advance the link info for the next element on the chain309chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;310311VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);312if (result != VK_SUCCESS) return result;313314struct instance_data *instance_data = new_instance_data(*pInstance);315vk_instance_dispatch_table_load(&instance_data->vtable,316fpGetInstanceProcAddr,317instance_data->instance);318319return result;320}321322static void nullhw_DestroyInstance(323VkInstance instance,324const VkAllocationCallbacks* pAllocator)325{326struct instance_data *instance_data = FIND(struct instance_data, instance);327instance_data->vtable.DestroyInstance(instance, pAllocator);328destroy_instance_data(instance_data);329}330331static const struct {332const char *name;333void *ptr;334} name_to_funcptr_map[] = {335{ "vkGetDeviceProcAddr", (void *) vkGetDeviceProcAddr },336#define ADD_HOOK(fn) { "vk" # fn, (void *) nullhw_ ## fn }337ADD_HOOK(CreateInstance),338ADD_HOOK(DestroyInstance),339ADD_HOOK(CreateDevice),340ADD_HOOK(DestroyDevice),341};342343static void *find_ptr(const char *name)344{345for (uint32_t i = 0; i < ARRAY_SIZE(name_to_funcptr_map); i++) {346if (strcmp(name, name_to_funcptr_map[i].name) == 0)347return name_to_funcptr_map[i].ptr;348}349350return NULL;351}352353VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev,354const char *funcName)355{356void *ptr = find_ptr(funcName);357if (ptr) return (PFN_vkVoidFunction)(ptr);358359if (dev == NULL) return NULL;360361struct device_data *device_data = FIND(struct device_data, dev);362if (device_data->vtable.GetDeviceProcAddr == NULL) return NULL;363return device_data->vtable.GetDeviceProcAddr(dev, funcName);364}365366VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance,367const char *funcName)368{369void *ptr = find_ptr(funcName);370if (ptr) return (PFN_vkVoidFunction) ptr;371372struct instance_data *instance_data = FIND(struct instance_data, instance);373if (instance_data->vtable.GetInstanceProcAddr == NULL) return NULL;374return instance_data->vtable.GetInstanceProcAddr(instance, funcName);375}376377378