Edit

IABSD.fr/xenocara/lib/mesa/src/intel/nullhw-layer/intel_nullhw.c

Branch :

  • Show log

    Commit

  • Author : jsg
    Date : 2025-06-05 11:23:11
    Hash : 67d6f117
    Message : Import Mesa 25.0.7

  • lib/mesa/src/intel/nullhw-layer/intel_nullhw.c
  • /*
     * Copyright © 2019 Intel Corporation
     *
     * Permission is hereby granted, free of charge, to any person obtaining a
     * copy of this software and associated documentation files (the "Software"),
     * to deal in the Software without restriction, including without limitation
     * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     * and/or sell copies of the Software, and to permit persons to whom the
     * Software is furnished to do so, subject to the following conditions:
     *
     * The above copyright notice and this permission notice (including the next
     * paragraph) shall be included in all copies or substantial portions of the
     * Software.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     * IN THE SOFTWARE.
     */
    
    #include <string.h>
    #include <stdlib.h>
    #include <assert.h>
    #include <stdio.h>
    
    #include <vulkan/vulkan.h>
    #include <vulkan/vk_layer.h>
    
    #include "util/u_debug.h"
    #include "util/hash_table.h"
    #include "util/macros.h"
    #include "util/simple_mtx.h"
    
    #include "vk_dispatch_table.h"
    #include "vk_enum_to_str.h"
    #include "vk_util.h"
    
    struct instance_data {
       struct vk_instance_dispatch_table vtable;
       VkInstance instance;
    };
    
    struct device_data {
       struct instance_data *instance;
    
       PFN_vkSetDeviceLoaderData set_device_loader_data;
    
       struct vk_device_dispatch_table vtable;
       VkPhysicalDevice physical_device;
       VkDevice device;
    };
    
    static struct hash_table_u64 *vk_object_to_data = NULL;
    static simple_mtx_t vk_object_to_data_mutex = SIMPLE_MTX_INITIALIZER;
    
    static inline void ensure_vk_object_map(void)
    {
       if (!vk_object_to_data)
          vk_object_to_data = _mesa_hash_table_u64_create(NULL);
    }
    
    #define HKEY(obj) ((uintptr_t)(obj))
    #define FIND(type, obj) ((type *)find_object_data(HKEY(obj)))
    
    static void *find_object_data(uint64_t obj)
    {
       simple_mtx_lock(&vk_object_to_data_mutex);
       ensure_vk_object_map();
       void *data = _mesa_hash_table_u64_search(vk_object_to_data, obj);
       simple_mtx_unlock(&vk_object_to_data_mutex);
       return data;
    }
    
    static void map_object(uint64_t obj, void *data)
    {
       simple_mtx_lock(&vk_object_to_data_mutex);
       ensure_vk_object_map();
       _mesa_hash_table_u64_insert(vk_object_to_data, obj, data);
       simple_mtx_unlock(&vk_object_to_data_mutex);
    }
    
    static void unmap_object(uint64_t obj)
    {
       simple_mtx_lock(&vk_object_to_data_mutex);
       _mesa_hash_table_u64_remove(vk_object_to_data, obj);
       simple_mtx_unlock(&vk_object_to_data_mutex);
    }
    
    /**/
    
    #define VK_CHECK(expr) \
       do { \
          VkResult __result = (expr); \
          if (__result != VK_SUCCESS) { \
             fprintf(stderr, "'%s' line %i failed with %s\n", \
                     #expr, __LINE__, vk_Result_to_str(__result)); \
          } \
       } while (0)
    
    /**/
    
    static void override_queue(struct device_data *device_data,
                               VkDevice device,
                               uint32_t queue_family_index,
                               VkQueue queue)
    {
       VkCommandPoolCreateInfo cmd_buffer_pool_info = {
          .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
          .queueFamilyIndex = queue_family_index,
       };
       VkCommandPool cmd_pool;
       VK_CHECK(device_data->vtable.CreateCommandPool(device,
                                                      &cmd_buffer_pool_info,
                                                      NULL, &cmd_pool));
    
    
       VkCommandBufferAllocateInfo cmd_buffer_info = {
          .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
          .commandPool = cmd_pool,
          .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
          .commandBufferCount = 1,
       };
       VkCommandBuffer cmd_buffer;
       VK_CHECK(device_data->vtable.AllocateCommandBuffers(device,
                                                           &cmd_buffer_info,
                                                           &cmd_buffer));
       VK_CHECK(device_data->set_device_loader_data(device, cmd_buffer));
    
       VkCommandBufferBeginInfo buffer_begin_info = {
          .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
       };
       device_data->vtable.BeginCommandBuffer(cmd_buffer, &buffer_begin_info);
    
       VkPerformanceOverrideInfoINTEL override_info = {
          .sType = VK_STRUCTURE_TYPE_PERFORMANCE_OVERRIDE_INFO_INTEL,
          .type = VK_PERFORMANCE_OVERRIDE_TYPE_NULL_HARDWARE_INTEL,
          .enable = VK_TRUE,
       };
       device_data->vtable.CmdSetPerformanceOverrideINTEL(cmd_buffer, &override_info);
    
       device_data->vtable.EndCommandBuffer(cmd_buffer);
    
       VkSubmitInfo submit_info = {
          .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
          .commandBufferCount = 1,
          .pCommandBuffers = &cmd_buffer,
       };
       VK_CHECK(device_data->vtable.QueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE));
    
       VK_CHECK(device_data->vtable.QueueWaitIdle(queue));
    
       device_data->vtable.DestroyCommandPool(device, cmd_pool, NULL);
    }
    
    static void device_override_queues(struct device_data *device_data,
                                       const VkDeviceCreateInfo *pCreateInfo)
    {
       for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++) {
          for (uint32_t j = 0; j < pCreateInfo->pQueueCreateInfos[i].queueCount; j++) {
             VkQueue queue;
             device_data->vtable.GetDeviceQueue(device_data->device,
                                                pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex,
                                                j, &queue);
    
             VK_CHECK(device_data->set_device_loader_data(device_data->device, queue));
    
             override_queue(device_data, device_data->device,
                            pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex, queue);
          }
       }
    }
    
    static VkLayerDeviceCreateInfo *get_device_chain_info(const VkDeviceCreateInfo *pCreateInfo,
                                                          VkLayerFunction func)
    {
       vk_foreach_struct_const(item, pCreateInfo->pNext) {
          if (item->sType == VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO &&
              ((VkLayerDeviceCreateInfo *) item)->function == func)
             return (VkLayerDeviceCreateInfo *)item;
       }
       unreachable("device chain info not found");
       return NULL;
    }
    
    static struct device_data *new_device_data(VkDevice device, struct instance_data *instance)
    {
       struct device_data *data = calloc(1, sizeof(*data));
       data->instance = instance;
       data->device = device;
       map_object(HKEY(data->device), data);
       return data;
    }
    
    static void destroy_device_data(struct device_data *data)
    {
       unmap_object(HKEY(data->device));
       free(data);
    }
    
    static VkResult nullhw_CreateDevice(
        VkPhysicalDevice                            physicalDevice,
        const VkDeviceCreateInfo*                   pCreateInfo,
        const VkAllocationCallbacks*                pAllocator,
        VkDevice*                                   pDevice)
    {
       VkLayerDeviceCreateInfo *chain_info =
          get_device_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
    
       assert(chain_info->u.pLayerInfo);
       PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
       PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;
       PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(NULL, "vkCreateDevice");
       if (fpCreateDevice == NULL) {
          return VK_ERROR_INITIALIZATION_FAILED;
       }
    
       // Advance the link info for the next element on the chain
       chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
    
       VkDeviceCreateInfo device_info = *pCreateInfo;
       const char **extensions = calloc(device_info.enabledExtensionCount + 1, sizeof(*extensions));
       bool found = false;
       for (uint32_t i = 0; i < device_info.enabledExtensionCount; i++) {
          if (!strcmp(device_info.ppEnabledExtensionNames[i], "VK_INTEL_performance_query")) {
             found = true;
             break;
          }
       }
       if (!found) {
          memcpy(extensions, device_info.ppEnabledExtensionNames,
                 sizeof(*extensions) * device_info.enabledExtensionCount);
          extensions[device_info.enabledExtensionCount++] = "VK_INTEL_performance_query";
          device_info.ppEnabledExtensionNames = extensions;
       }
    
       VkResult result = fpCreateDevice(physicalDevice, &device_info, pAllocator, pDevice);
       free(extensions);
       if (result != VK_SUCCESS) return result;
    
       struct instance_data *instance_data = FIND(struct instance_data, physicalDevice);
       struct device_data *device_data = new_device_data(*pDevice, instance_data);
       device_data->physical_device = physicalDevice;
       vk_device_dispatch_table_load(&device_data->vtable, fpGetDeviceProcAddr, *pDevice);
    
       VkLayerDeviceCreateInfo *load_data_info =
          get_device_chain_info(pCreateInfo, VK_LOADER_DATA_CALLBACK);
       device_data->set_device_loader_data = load_data_info->u.pfnSetDeviceLoaderData;
    
       device_override_queues(device_data, pCreateInfo);
    
       return result;
    }
    
    static void nullhw_DestroyDevice(
        VkDevice                                    device,
        const VkAllocationCallbacks*                pAllocator)
    {
       struct device_data *device_data = FIND(struct device_data, device);
       device_data->vtable.DestroyDevice(device, pAllocator);
       destroy_device_data(device_data);
    }
    
    static struct instance_data *new_instance_data(VkInstance instance)
    {
       struct instance_data *data = calloc(1, sizeof(*data));
       data->instance = instance;
       map_object(HKEY(data->instance), data);
       return data;
    }
    
    static void destroy_instance_data(struct instance_data *data)
    {
       unmap_object(HKEY(data->instance));
       free(data);
    }
    
    static VkLayerInstanceCreateInfo *get_instance_chain_info(const VkInstanceCreateInfo *pCreateInfo,
                                                              VkLayerFunction func)
    {
       vk_foreach_struct_const(item, pCreateInfo->pNext) {
          if (item->sType == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO &&
              ((VkLayerInstanceCreateInfo *) item)->function == func)
             return (VkLayerInstanceCreateInfo *) item;
       }
       unreachable("instance chain info not found");
       return NULL;
    }
    
    static VkResult nullhw_CreateInstance(
        const VkInstanceCreateInfo*                 pCreateInfo,
        const VkAllocationCallbacks*                pAllocator,
        VkInstance*                                 pInstance)
    {
       VkLayerInstanceCreateInfo *chain_info =
          get_instance_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
    
       assert(chain_info->u.pLayerInfo);
       PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr =
          chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
       PFN_vkCreateInstance fpCreateInstance =
          (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance");
       if (fpCreateInstance == NULL) {
          return VK_ERROR_INITIALIZATION_FAILED;
       }
    
       // Advance the link info for the next element on the chain
       chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
    
       VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
       if (result != VK_SUCCESS) return result;
    
       struct instance_data *instance_data = new_instance_data(*pInstance);
       vk_instance_dispatch_table_load(&instance_data->vtable,
                                       fpGetInstanceProcAddr,
                                       instance_data->instance);
    
       return result;
    }
    
    static void nullhw_DestroyInstance(
        VkInstance                                  instance,
        const VkAllocationCallbacks*                pAllocator)
    {
       struct instance_data *instance_data = FIND(struct instance_data, instance);
       instance_data->vtable.DestroyInstance(instance, pAllocator);
       destroy_instance_data(instance_data);
    }
    
    static const struct {
       const char *name;
       void *ptr;
    } name_to_funcptr_map[] = {
       { "vkGetDeviceProcAddr", (void *) vkGetDeviceProcAddr },
    #define ADD_HOOK(fn) { "vk" # fn, (void *) nullhw_ ## fn }
       ADD_HOOK(CreateInstance),
       ADD_HOOK(DestroyInstance),
       ADD_HOOK(CreateDevice),
       ADD_HOOK(DestroyDevice),
    };
    
    static void *find_ptr(const char *name)
    {
       for (uint32_t i = 0; i < ARRAY_SIZE(name_to_funcptr_map); i++) {
          if (strcmp(name, name_to_funcptr_map[i].name) == 0)
             return name_to_funcptr_map[i].ptr;
       }
    
       return NULL;
    }
    
    PUBLIC VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev,
                                                                        const char *funcName)
    {
       void *ptr = find_ptr(funcName);
       if (ptr) return (PFN_vkVoidFunction)(ptr);
    
       if (dev == NULL) return NULL;
    
       struct device_data *device_data = FIND(struct device_data, dev);
       if (device_data->vtable.GetDeviceProcAddr == NULL) return NULL;
       return device_data->vtable.GetDeviceProcAddr(dev, funcName);
    }
    
    PUBLIC VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance,
                                                                          const char *funcName)
    {
       void *ptr = find_ptr(funcName);
       if (ptr) return (PFN_vkVoidFunction) ptr;
    
       struct instance_data *instance_data = FIND(struct instance_data, instance);
       if (instance_data->vtable.GetInstanceProcAddr == NULL) return NULL;
       return instance_data->vtable.GetInstanceProcAddr(instance, funcName);
    }