loader.c revision 4b7f35fc3bb104e0607102798b4e3cff9990ade3
11be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania/* 21be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * Vulkan 31be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * 41be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * Copyright (C) 2014 LunarG, Inc. 51be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * 61be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * Permission is hereby granted, free of charge, to any person obtaining a 71be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * copy of this software and associated documentation files (the "Software"), 81be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * to deal in the Software without restriction, including without limitation 91be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * the rights to use, copy, modify, merge, publish, distribute, sublicense, 101be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * and/or sell copies of the Software, and to permit persons to whom the 111be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * Software is furnished to do so, subject to the following conditions: 121be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * 131be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * The above copyright notice and this permission notice shall be included 141be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * in all copies or substantial portions of the Software. 151be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * 161be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 171be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 181be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 191be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 201be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 211be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 221be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * DEALINGS IN THE SOFTWARE. 231be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * 241be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * Authors: 251be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * Chia-I Wu <olv@lunarg.com> 261be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * Jon Ashburn <jon@lunarg.com> 271be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * Courtney Goeltzenleuchter <courtney@lunarg.com> 281be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * Ian Elliott <ian@lunarg.com> 291be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania */ 301be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania#define _GNU_SOURCE 311be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania#include <stdio.h> 321be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania#include <stdlib.h> 331be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania#include <stdarg.h> 341be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania#include <stdbool.h> 351be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania#include <string.h> 3641d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot 371be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania#include <sys/types.h> 3841d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot#if defined(WIN32) 391be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania#include "dirent_on_windows.h" 4041d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot#else // WIN32 411be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania#include <dirent.h> 4241d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot#endif // WIN32 431be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania#include "vk_loader_platform.h" 4441d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot#include "loader.h" 4541d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot#include "gpa_helper.h" 461be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania#include "table_ops.h" 471be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania#include "debug_report.h" 481be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania#include "vk_icd.h" 491be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania#include "cJSON.h" 501be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania 511be2c9def7187e4e643c00a31dd9986395795d7dNicolas Cataniavoid loader_add_to_ext_list( 5241d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot struct loader_extension_list *ext_list, 531be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania uint32_t prop_list_count, 5441d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot const struct loader_extension_property *prop_list); 551be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania 5641d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabotstatic loader_platform_dl_handle loader_add_layer_lib( 5741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot const char *chain_type, 5841d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot struct loader_layer_properties *layer_prop); 59fc2de66453b0669c09eaca643b07d34443858b6fElliott Hughes 60fc2de66453b0669c09eaca643b07d34443858b6fElliott Hughesstatic void loader_remove_layer_lib( 61fc2de66453b0669c09eaca643b07d34443858b6fElliott Hughes struct loader_instance *inst, 62fc2de66453b0669c09eaca643b07d34443858b6fElliott Hughes struct loader_layer_properties *layer_prop); 63fc2de66453b0669c09eaca643b07d34443858b6fElliott Hughes 64fc2de66453b0669c09eaca643b07d34443858b6fElliott Hughesstruct loader_struct loader = {0}; 65fc2de66453b0669c09eaca643b07d34443858b6fElliott Hughes 66fc2de66453b0669c09eaca643b07d34443858b6fElliott Hughesstatic PFN_vkVoidFunction VKAPI loader_GetInstanceProcAddr(VkInstance instance, const char * pName); 67fc2de66453b0669c09eaca643b07d34443858b6fElliott Hughesstatic bool loader_init_ext_list(struct loader_extension_list *ext_info); 68fc2de66453b0669c09eaca643b07d34443858b6fElliott Hughes 69fc2de66453b0669c09eaca643b07d34443858b6fElliott Hughesenum loader_debug { 70fc2de66453b0669c09eaca643b07d34443858b6fElliott Hughes LOADER_INFO_BIT = 0x01, 71fc2de66453b0669c09eaca643b07d34443858b6fElliott Hughes LOADER_WARN_BIT = 0x02, 72fc2de66453b0669c09eaca643b07d34443858b6fElliott Hughes LOADER_PERF_BIT = 0x04, 73fc2de66453b0669c09eaca643b07d34443858b6fElliott Hughes LOADER_ERROR_BIT = 0x08, 7441d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot LOADER_DEBUG_BIT = 0x10, 7541d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot}; 7641d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot 7741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabotuint32_t g_loader_debug = 0; 7841d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabotuint32_t g_loader_log_msgs = 0; 7941d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot 8041d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot//thread safety lock for accessing global data structures such as "loader" 8141d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot// all entrypoints on the instance chain need to be locked except GPA 8241d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot// additionally CreateDevice and DestroyDevice needs to be locked 831be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catanialoader_platform_thread_mutex loader_lock; 841be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania 851be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania// This table contains the loader's instance dispatch table, which contains 861be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania// default functions if no instance layers are activated. This contains 871be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania// pointers to "terminator functions". 881be2c9def7187e4e643c00a31dd9986395795d7dNicolas Cataniaconst VkLayerInstanceDispatchTable instance_disp = { 8941d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot .GetInstanceProcAddr = loader_GetInstanceProcAddr, 9041d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot .CreateInstance = loader_CreateInstance, 9141d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot .DestroyInstance = loader_DestroyInstance, 921be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania .EnumeratePhysicalDevices = loader_EnumeratePhysicalDevices, 931be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania .GetPhysicalDeviceFeatures = loader_GetPhysicalDeviceFeatures, 941be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania .GetPhysicalDeviceFormatProperties = loader_GetPhysicalDeviceFormatProperties, 951be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania .GetPhysicalDeviceImageFormatProperties = loader_GetPhysicalDeviceImageFormatProperties, 961be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania .GetPhysicalDeviceLimits = loader_GetPhysicalDeviceLimits, 971be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania .GetPhysicalDeviceProperties = loader_GetPhysicalDeviceProperties, 981be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania .GetPhysicalDeviceQueueCount = loader_GetPhysicalDeviceQueueCount, 991be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania .GetPhysicalDeviceQueueProperties = loader_GetPhysicalDeviceQueueProperties, 1001be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania .GetPhysicalDeviceMemoryProperties = loader_GetPhysicalDeviceMemoryProperties, 1011be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania .GetPhysicalDeviceExtensionProperties = loader_GetPhysicalDeviceExtensionProperties, 1021be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania .GetPhysicalDeviceLayerProperties = loader_GetPhysicalDeviceLayerProperties, 1031be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania .GetPhysicalDeviceSparseImageFormatProperties = loader_GetPhysicalDeviceSparseImageFormatProperties, 1041be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania .GetPhysicalDeviceSurfaceSupportWSI = loader_GetPhysicalDeviceSurfaceSupportWSI, 1051be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania .DbgCreateMsgCallback = loader_DbgCreateMsgCallback, 1061be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania .DbgDestroyMsgCallback = loader_DbgDestroyMsgCallback, 1071be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania}; 1081be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania 1091be2c9def7187e4e643c00a31dd9986395795d7dNicolas CataniaLOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_icd); 1101be2c9def7187e4e643c00a31dd9986395795d7dNicolas CataniaLOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_layer); 1111be2c9def7187e4e643c00a31dd9986395795d7dNicolas CataniaLOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_exts); 1121be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania 1131be2c9def7187e4e643c00a31dd9986395795d7dNicolas Cataniavoid* loader_heap_alloc( 1141be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania struct loader_instance *instance, 1151be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania size_t size, 1161be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania VkSystemAllocType alloc_type) 1171be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania{ 1181be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania if (instance && instance->alloc_callbacks.pfnAlloc) { 1191be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania /* TODO: What should default alignment be? 1, 4, 8, other? */ 1201be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania return instance->alloc_callbacks.pfnAlloc(instance->alloc_callbacks.pUserData, size, 4, alloc_type); 1211be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania } 1221be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania return malloc(size); 1231be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania} 1241be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania 1251be2c9def7187e4e643c00a31dd9986395795d7dNicolas Cataniavoid* loader_aligned_heap_alloc( 1261be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania struct loader_instance *instance, 1271be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania size_t size, 1281be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania size_t alignment, 12941d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot VkSystemAllocType alloc_type) 1301be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania{ 1311be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania if (!instance && instance->alloc_callbacks.pfnAlloc) { 1321be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania return instance->alloc_callbacks.pfnAlloc(instance->alloc_callbacks.pUserData, size, alignment, alloc_type); 1331be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania } 1341be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania#if defined(_WIN32) 13541d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot return _aligned_malloc(alignment, size); 13641d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot#else 13741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot return aligned_alloc(alignment, size); 13841d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot#endif 13941d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot} 14041d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot 14141d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabotvoid loader_heap_free( 14241d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot struct loader_instance *instance, 14341d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot void *pMem) 14441d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot{ 14541d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot if (!instance && instance->alloc_callbacks.pfnFree) { 14641d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot instance->alloc_callbacks.pfnFree(instance->alloc_callbacks.pUserData, pMem); 14741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot } 14841d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot free(pMem); 14941d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot} 15041d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot 15141d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabotstatic void loader_log(VkFlags msg_type, int32_t msg_code, 15241d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot const char *format, ...) 15341d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot{ 15441d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot char msg[512]; 15541d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot va_list ap; 15641d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot int ret; 15741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot 15841d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot if (!(msg_type & g_loader_log_msgs)) { 15941d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot return; 16041d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot } 16141d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot 16241d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot va_start(ap, format); 16341d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot ret = vsnprintf(msg, sizeof(msg), format, ap); 16441d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot if ((ret >= (int) sizeof(msg)) || ret < 0) { 16541d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot msg[sizeof(msg)-1] = '\0'; 16641d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot } 16741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot va_end(ap); 16841d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot 16941d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot#if defined(WIN32) 17041d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot OutputDebugString(msg); 17141d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot OutputDebugString("\n"); 17241d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot#endif 17341d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot fputs(msg, stderr); 17441d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot fputc('\n', stderr); 17541d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot} 17641d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot 17741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot#if defined(WIN32) 17841d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabotstatic char *loader_get_next_path(char *path); 17941d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot/** 18041d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot* Find the list of registry files (names within a key) in key "location". 18141d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot* 18241d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot* This function looks in the registry (hive = DEFAULT_VK_REGISTRY_HIVE) key as given in "location" 18341d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot* for a list or name/values which are added to a returned list (function return value). 18441d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot* The DWORD values within the key must be 0 or they are skipped. 1851be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania* Function return is a string with a ';' seperated list of filenames. 1861be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania* Function return is NULL if no valid name/value pairs are found in the key, 1871be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania* or the key is not found. 1881be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania* 1891be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania* \returns 1901be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania* A string list of filenames as pointer. 1911be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania* When done using the returned string list, pointer should be freed. 1921be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania*/ 1931be2c9def7187e4e643c00a31dd9986395795d7dNicolas Cataniastatic char *loader_get_registry_files(char *location) 1941be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania{ 1951be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania LONG rtn_value; 1961be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania HKEY hive, key; 1971be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania DWORD access_flags = KEY_QUERY_VALUE; 1981be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania char name[2048]; 1991be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania char *out = NULL; 2001be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania char *loc = location; 2011be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania char *next; 2021be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania DWORD idx = 0; 2031be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania DWORD name_size = sizeof(name); 2041be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania DWORD value; 2051be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania DWORD total_size = 4096; 2061be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania DWORD value_size = sizeof(value); 2071be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania 20841d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot while(*loc) 2091be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania { 21041d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot next = loader_get_next_path(loc); 21141d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot hive = DEFAULT_VK_REGISTRY_HIVE; 2121be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania rtn_value = RegOpenKeyEx(hive, loc, 0, access_flags, &key); 2131be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania if (rtn_value != ERROR_SUCCESS) { 21441d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot // We didn't find the key. Try the 32-bit hive (where we've seen the 21541d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot // key end up on some people's systems): 21641d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot access_flags |= KEY_WOW64_32KEY; 21741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot rtn_value = RegOpenKeyEx(hive, loc, 0, access_flags, &key); 21841d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot if (rtn_value != ERROR_SUCCESS) { 21941d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot // We still couldn't find the key, so give up: 22041d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot loc = next; 22141d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot continue; 22241d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot } 22341d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot } 22441d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot 22541d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot while((rtn_value = RegEnumValue(key, idx++, name, &name_size, NULL, NULL, (LPBYTE) &value, &value_size)) == ERROR_SUCCESS) { 22641d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot if (value_size == sizeof(value) && value == 0) { 22741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot if (out == NULL) { 22841d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot out = malloc(total_size); 22941d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot out[0] = '\0'; 2301be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania } 2311be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania else if (strlen(out) + name_size + 1 > total_size) { 2321be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania out = realloc(out, total_size * 2); 2331be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania total_size *= 2; 2341be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania } 2351be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania if (out == NULL) { 2361be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory, failed loader_get_registry_files"); 2371be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania return NULL; 2381be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania } 2391be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania if (strlen(out) == 0) 24041d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot snprintf(out, name_size + 1, "%s", name); 24141d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot else 24241d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot snprintf(out + strlen(out), name_size + 2, "%c%s", PATH_SEPERATOR, name); 24341d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot } 24441d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot name_size = 2048; 2451be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania } 24641d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot loc = next; 24741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot } 2481be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania 2491be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania return out; 2501be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania} 2511be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania 2521be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania#endif // WIN32 2531be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania 25441d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot/** 25541d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot * Given string of three part form "maj.min.pat" convert to a vulkan version 25641d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot * number. 25741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot */ 25841d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabotstatic uint32_t loader_make_version(const char *vers_str) 259fc2de66453b0669c09eaca643b07d34443858b6fElliott Hughes{ 26041d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot uint32_t vers = 0, major, minor, patch; 26141d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot char *minor_str= NULL; 26241d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot char *patch_str = NULL; 26341d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot char *cstr; 26441d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot char *str; 26541d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot 26641d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot if (!vers_str) 26741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot return vers; 26841d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot cstr = loader_stack_alloc(strlen(vers_str) + 1); 26941d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot strcpy(cstr, vers_str); 27041d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot while ((str = strchr(cstr, '.')) != NULL) { 2711be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania if (minor_str == NULL) { 2721be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania minor_str = str + 1; 2731be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania *str = '\0'; 27441d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot major = atoi(cstr); 27541d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot } 27641d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot else if (patch_str == NULL) { 27741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot patch_str = str + 1; 2781be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania *str = '\0'; 2791be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania minor = atoi(minor_str); 2801be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania } 2811be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania else { 2821be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania return vers; 28341d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot } 28441d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot cstr = str + 1; 28541d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot } 28641d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot patch = atoi(patch_str); 28741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot 28841d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot return VK_MAKE_VERSION(major, minor, patch); 2891be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania 2901be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania} 2911be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania 2921be2c9def7187e4e643c00a31dd9986395795d7dNicolas Cataniabool compare_vk_extension_properties(const VkExtensionProperties *op1, const VkExtensionProperties *op2) 2931be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania{ 2941be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania return strcmp(op1->extName, op2->extName) == 0 ? true : false; 2951be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania} 2961be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania 2971be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania/** 2981be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * Search the given ext_array for an extension 2991be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania * matching the given vk_ext_prop 3001be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania */ 3011be2c9def7187e4e643c00a31dd9986395795d7dNicolas Cataniabool has_vk_extension_property_array( 3021be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania const VkExtensionProperties *vk_ext_prop, 3031be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania const uint32_t count, 3041be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania const VkExtensionProperties *ext_array) 3051be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania{ 3061be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania for (uint32_t i = 0; i < count; i++) { 3071be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania if (compare_vk_extension_properties(vk_ext_prop, &ext_array[i])) 3081be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania return true; 3091be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania } 3101be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania return false; 3111be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania} 3121be2c9def7187e4e643c00a31dd9986395795d7dNicolas Catania 31341d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot/** 31441d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot * Search the given ext_list for an extension 31541d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot * matching the given vk_ext_prop 31641d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot */ 31741d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabotbool has_vk_extension_property( 31841d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot const VkExtensionProperties *vk_ext_prop, 31941d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot const struct loader_extension_list *ext_list) 32041d0579e8de9ef4ff178fc4991043c61a19943f7Brett Chabot{ 321 for (uint32_t i = 0; i < ext_list->count; i++) { 322 if (compare_vk_extension_properties(&ext_list->list[i].info, vk_ext_prop)) 323 return true; 324 } 325 return false; 326} 327 328static inline bool loader_is_layer_type_device(const enum layer_type type) { 329 if ((type & VK_LAYER_TYPE_DEVICE_EXPLICIT) || 330 (type & VK_LAYER_TYPE_DEVICE_IMPLICIT)) 331 return true; 332 return false; 333} 334 335/* 336 * Search the given layer list for a layer matching the given layer name 337 */ 338static struct loader_layer_properties *get_layer_property( 339 const char *name, 340 const struct loader_layer_list *layer_list) 341{ 342 for (uint32_t i = 0; i < layer_list->count; i++) { 343 const VkLayerProperties *item = &layer_list->list[i].info; 344 if (strcmp(name, item->layerName) == 0) 345 return &layer_list->list[i]; 346 } 347 return NULL; 348} 349 350static void loader_add_global_extensions( 351 const PFN_vkGetGlobalExtensionProperties fp_get_props, 352 const char *lib_name, 353 const loader_platform_dl_handle lib_handle, 354 const enum extension_origin origin, 355 struct loader_extension_list *ext_list) 356{ 357 uint32_t i, count; 358 struct loader_extension_property ext_props; 359 VkExtensionProperties *extension_properties; 360 VkResult res; 361 362 if (!fp_get_props) { 363 /* No GetGlobalExtensionProperties defined */ 364 return; 365 } 366 367 res = fp_get_props(NULL, &count, NULL); 368 if (res != VK_SUCCESS) { 369 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting global extension count from %s", lib_name); 370 return; 371 } 372 373 if (count == 0) { 374 /* No ExtensionProperties to report */ 375 return; 376 } 377 378 extension_properties = loader_stack_alloc(count * sizeof(VkExtensionProperties)); 379 380 res = fp_get_props(NULL, &count, extension_properties); 381 if (res != VK_SUCCESS) { 382 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting global extensions from %s", lib_name); 383 return; 384 } 385 386 for (i = 0; i < count; i++) { 387 memset(&ext_props, 0, sizeof(ext_props)); 388 memcpy(&ext_props.info, &extension_properties[i], sizeof(VkExtensionProperties)); 389 //TODO eventually get this from the layer config file 390 ext_props.origin = origin; 391 ext_props.lib_name = lib_name; 392 393 char spec_version[64]; 394 395 snprintf(spec_version, sizeof(spec_version), "%d.%d.%d", 396 VK_MAJOR(ext_props.info.specVersion), 397 VK_MINOR(ext_props.info.specVersion), 398 VK_PATCH(ext_props.info.specVersion)); 399 400 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, 401 "Global Extension: %s (%s) version %s", 402 ext_props.info.extName, lib_name, spec_version); 403 loader_add_to_ext_list(ext_list, 1, &ext_props); 404 } 405 406 return; 407} 408 409static void loader_add_physical_device_extensions( 410 PFN_vkGetPhysicalDeviceExtensionProperties get_phys_dev_ext_props, 411 VkPhysicalDevice physical_device, 412 const enum extension_origin origin, 413 const char *lib_name, 414 struct loader_extension_list *ext_list) 415{ 416 uint32_t i, count; 417 VkResult res; 418 struct loader_extension_property ext_props; 419 VkExtensionProperties *extension_properties; 420 421 memset(&ext_props, 0, sizeof(ext_props)); 422 ext_props.origin = origin; 423 ext_props.lib_name = lib_name; 424 425 if (get_phys_dev_ext_props) { 426 res = get_phys_dev_ext_props(physical_device, NULL, &count, NULL); 427 if (res == VK_SUCCESS && count > 0) { 428 429 extension_properties = loader_stack_alloc(count * sizeof(VkExtensionProperties)); 430 431 res = get_phys_dev_ext_props(physical_device, NULL, &count, extension_properties); 432 for (i = 0; i < count; i++) { 433 char spec_version[64]; 434 435 memcpy(&ext_props.info, &extension_properties[i], sizeof(VkExtensionProperties)); 436 437 snprintf(spec_version, sizeof(spec_version), "%d.%d.%d", 438 VK_MAJOR(ext_props.info.specVersion), 439 VK_MINOR(ext_props.info.specVersion), 440 VK_PATCH(ext_props.info.specVersion)); 441 442 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, 443 "PhysicalDevice Extension: %s (%s) version %s", 444 ext_props.info.extName, lib_name, spec_version); 445 loader_add_to_ext_list(ext_list, 1, &ext_props); 446 } 447 } else { 448 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Error getting physical device extension info count from Layer %s", ext_props.lib_name); 449 } 450 } 451 452 return; 453} 454 455static bool loader_init_ext_list(struct loader_extension_list *ext_info) 456{ 457 ext_info->capacity = 32 * sizeof(struct loader_extension_property); 458 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */ 459 ext_info->list = malloc(ext_info->capacity); 460 if (ext_info->list == NULL) { 461 return false; 462 } 463 memset(ext_info->list, 0, ext_info->capacity); 464 ext_info->count = 0; 465 return true; 466} 467 468void loader_destroy_ext_list(struct loader_extension_list *ext_info) 469{ 470 free(ext_info->list); 471 ext_info->count = 0; 472 ext_info->capacity = 0; 473} 474 475/** 476 * Search the given search_list for any layers in the props list. 477 * Add these to the output layer_list. Don't add duplicates to the output layer_list. 478 */ 479static VkResult loader_add_layer_names_to_list( 480 struct loader_layer_list *output_list, 481 uint32_t name_count, 482 const char * const *names, 483 const struct loader_layer_list *search_list) 484{ 485 struct loader_layer_properties *layer_prop; 486 VkResult err = VK_SUCCESS; 487 488 for (uint32_t i = 0; i < name_count; i++) { 489 const char *search_target = names[i]; 490 layer_prop = get_layer_property(search_target, search_list); 491 if (!layer_prop) { 492 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Unable to find layer %s", search_target); 493 err = VK_ERROR_INVALID_LAYER; 494 continue; 495 } 496 497 loader_add_to_layer_list(output_list, 1, layer_prop); 498 } 499 500 return err; 501} 502 503/* 504 * Append non-duplicate extension properties defined in props 505 * to the given ext_list. 506 */ 507void loader_add_to_ext_list( 508 struct loader_extension_list *ext_list, 509 uint32_t prop_list_count, 510 const struct loader_extension_property *props) 511{ 512 uint32_t i; 513 struct loader_extension_property *cur_ext; 514 515 if (ext_list->list == NULL || ext_list->capacity == 0) { 516 loader_init_ext_list(ext_list); 517 } 518 519 if (ext_list->list == NULL) 520 return; 521 522 for (i = 0; i < prop_list_count; i++) { 523 cur_ext = (struct loader_extension_property *) &props[i]; 524 525 // look for duplicates 526 if (has_vk_extension_property(&cur_ext->info, ext_list)) { 527 continue; 528 } 529 530 // add to list at end 531 // check for enough capacity 532 if (ext_list->count * sizeof(struct loader_extension_property) 533 >= ext_list->capacity) { 534 // double capacity 535 ext_list->capacity *= 2; 536 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */ 537 ext_list->list = realloc(ext_list->list, ext_list->capacity); 538 } 539 540 memcpy(&ext_list->list[ext_list->count], cur_ext, sizeof(struct loader_extension_property)); 541 ext_list->count++; 542 } 543} 544 545/* 546 * Manage lists of VkLayerProperties 547 */ 548static bool loader_init_layer_list(struct loader_layer_list *list) 549{ 550 list->capacity = 32 * sizeof(struct loader_layer_properties); 551 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */ 552 list->list = malloc(list->capacity); 553 if (list->list == NULL) { 554 return false; 555 } 556 memset(list->list, 0, list->capacity); 557 list->count = 0; 558 return true; 559} 560 561void loader_destroy_layer_list(struct loader_layer_list *layer_list) 562{ 563 free(layer_list->list); 564 layer_list->count = 0; 565 layer_list->capacity = 0; 566} 567 568/* 569 * Manage list of layer libraries (loader_lib_info) 570 */ 571static bool loader_init_layer_library_list(struct loader_layer_library_list *list) 572{ 573 list->capacity = 32 * sizeof(struct loader_lib_info); 574 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */ 575 list->list = malloc(list->capacity); 576 if (list->list == NULL) { 577 return false; 578 } 579 memset(list->list, 0, list->capacity); 580 list->count = 0; 581 return true; 582} 583 584void loader_destroy_layer_library_list(struct loader_layer_library_list *list) 585{ 586 for (uint32_t i = 0; i < list->count; i++) { 587 free(list->list[i].lib_name); 588 } 589 free(list->list); 590 list->count = 0; 591 list->capacity = 0; 592} 593 594void loader_add_to_layer_library_list( 595 struct loader_layer_library_list *list, 596 uint32_t item_count, 597 const struct loader_lib_info *new_items) 598{ 599 uint32_t i; 600 struct loader_lib_info *item; 601 602 if (list->list == NULL || list->capacity == 0) { 603 loader_init_layer_library_list(list); 604 } 605 606 if (list->list == NULL) 607 return; 608 609 for (i = 0; i < item_count; i++) { 610 item = (struct loader_lib_info *) &new_items[i]; 611 612 // look for duplicates 613 for (uint32_t j = 0; j < list->count; j++) { 614 if (strcmp(list->list[i].lib_name, new_items->lib_name) == 0) { 615 continue; 616 } 617 } 618 619 // add to list at end 620 // check for enough capacity 621 if (list->count * sizeof(struct loader_lib_info) 622 >= list->capacity) { 623 // double capacity 624 list->capacity *= 2; 625 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */ 626 list->list = realloc(list->list, list->capacity); 627 } 628 629 memcpy(&list->list[list->count], item, sizeof(struct loader_lib_info)); 630 list->count++; 631 } 632} 633 634 635/* 636 * Search the given layer list for a list 637 * matching the given VkLayerProperties 638 */ 639bool has_vk_layer_property( 640 const VkLayerProperties *vk_layer_prop, 641 const struct loader_layer_list *list) 642{ 643 for (uint32_t i = 0; i < list->count; i++) { 644 if (strcmp(vk_layer_prop->layerName, list->list[i].info.layerName) == 0) 645 return true; 646 } 647 return false; 648} 649 650/* 651 * Search the given layer list for a layer 652 * matching the given name 653 */ 654bool has_layer_name( 655 const char *name, 656 const struct loader_layer_list *list) 657{ 658 for (uint32_t i = 0; i < list->count; i++) { 659 if (strcmp(name, list->list[i].info.layerName) == 0) 660 return true; 661 } 662 return false; 663} 664 665/* 666 * Append non-duplicate layer properties defined in prop_list 667 * to the given layer_info list 668 */ 669void loader_add_to_layer_list( 670 struct loader_layer_list *list, 671 uint32_t prop_list_count, 672 const struct loader_layer_properties *props) 673{ 674 uint32_t i; 675 struct loader_layer_properties *layer; 676 677 if (list->list == NULL || list->capacity == 0) { 678 loader_init_layer_list(list); 679 } 680 681 if (list->list == NULL) 682 return; 683 684 for (i = 0; i < prop_list_count; i++) { 685 layer = (struct loader_layer_properties *) &props[i]; 686 687 // look for duplicates 688 if (has_vk_layer_property(&layer->info, list)) { 689 continue; 690 } 691 692 // add to list at end 693 // check for enough capacity 694 if (list->count * sizeof(struct loader_layer_properties) 695 >= list->capacity) { 696 // double capacity 697 list->capacity *= 2; 698 list->list = realloc(list->list, list->capacity); 699 } 700 701 memcpy(&list->list[list->count], layer, sizeof(struct loader_layer_properties)); 702 list->count++; 703 } 704} 705 706/** 707 * Search the search_list for any layer with a name 708 * that matches the given name and a type that matches the given type 709 * Add all matching layers to the found_list 710 * Do not add if found loader_layer_properties is already 711 * on the found_list. 712 */ 713static void loader_find_layer_name_add_list( 714 const char *name, 715 const enum layer_type type, 716 const struct loader_layer_list *search_list, 717 struct loader_layer_list *found_list) 718{ 719 for (uint32_t i = 0; i < search_list->count; i++) { 720 struct loader_layer_properties *layer_prop = &search_list->list[i]; 721 if (0 == strcmp(layer_prop->info.layerName, name) && 722 (layer_prop->type & type)) { 723 /* Found a layer with the same name, add to found_list */ 724 loader_add_to_layer_list(found_list, 1, layer_prop); 725 } 726 } 727} 728 729static struct loader_extension_property *get_extension_property( 730 const char *name, 731 const struct loader_extension_list *list) 732{ 733 for (uint32_t i = 0; i < list->count; i++) { 734 const VkExtensionProperties *item = &list->list[i].info; 735 if (strcmp(name, item->extName) == 0) 736 return &list->list[i]; 737 } 738 return NULL; 739} 740 741/* 742 * For global exenstions implemented within the loader (i.e. DEBUG_REPORT 743 * the extension must provide two entry points for the loader to use: 744 * - "trampoline" entry point - this is the address returned by GetProcAddr 745 * and will always do what's necessary to support a global call. 746 * - "terminator" function - this function will be put at the end of the 747 * instance chain and will contain the necessary logica to call / process 748 * the extension for the appropriate ICDs that are available. 749 * There is no generic mechanism for including these functions, the references 750 * must be placed into the appropriate loader entry points. 751 * GetInstanceProcAddr: call extension GetInstanceProcAddr to check for GetProcAddr requests 752 * loader_coalesce_extensions(void) - add extension records to the list of global 753 * extension available to the app. 754 * instance_disp - add function pointer for terminator function to this array. 755 * The extension itself should be in a separate file that will be 756 * linked directly with the loader. 757 */ 758void loader_coalesce_extensions(void) 759{ 760 struct loader_scanned_icds *icd_list = loader.scanned_icd_list; 761 762 // traverse scanned icd list adding non-duplicate extensions to the list 763 while (icd_list != NULL) { 764 loader_add_to_ext_list(&loader.global_extensions, 765 icd_list->global_extension_list.count, 766 icd_list->global_extension_list.list); 767 icd_list = icd_list->next; 768 }; 769 770 // Traverse loader's extensions, adding non-duplicate extensions to the list 771 wsi_swapchain_add_instance_extensions(&loader.global_extensions); 772 debug_report_add_instance_extensions(&loader.global_extensions); 773} 774 775static struct loader_icd *loader_get_icd_and_device(const VkDevice device, 776 struct loader_device **found_dev) 777{ 778 *found_dev = NULL; 779 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) { 780 for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) { 781 for (struct loader_device *dev = icd->logical_device_list; dev; dev = dev->next) 782 if (dev->device == device) { 783 *found_dev = dev; 784 return icd; 785 } 786 } 787 } 788 return NULL; 789} 790 791static void loader_destroy_logical_device(struct loader_device *dev) 792{ 793 free(dev->app_extension_props); 794 if (dev->activated_layer_list.count) 795 loader_destroy_layer_list(&dev->activated_layer_list); 796 free(dev); 797} 798 799static struct loader_device *loader_add_logical_device(const VkDevice dev, struct loader_device **device_list) 800{ 801 struct loader_device *new_dev; 802 803 new_dev = malloc(sizeof(struct loader_device)); 804 if (!new_dev) { 805 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc struct laoder-device"); 806 return NULL; 807 } 808 809 memset(new_dev, 0, sizeof(struct loader_device)); 810 811 new_dev->next = *device_list; 812 new_dev->device = dev; 813 *device_list = new_dev; 814 return new_dev; 815} 816 817void loader_remove_logical_device(VkDevice device) 818{ 819 struct loader_device *found_dev, *dev, *prev_dev; 820 struct loader_icd *icd; 821 icd = loader_get_icd_and_device(device, &found_dev); 822 823 if (!icd || !found_dev) 824 return; 825 826 prev_dev = NULL; 827 dev = icd->logical_device_list; 828 while (dev && dev != found_dev) { 829 prev_dev = dev; 830 dev = dev->next; 831 } 832 833 if (prev_dev) 834 prev_dev->next = found_dev->next; 835 else 836 icd->logical_device_list = found_dev->next; 837 loader_destroy_logical_device(found_dev); 838} 839 840 841static void loader_icd_destroy( 842 struct loader_instance *ptr_inst, 843 struct loader_icd *icd) 844{ 845 ptr_inst->total_icd_count--; 846 free(icd->gpus); 847 for (struct loader_device *dev = icd->logical_device_list; dev; ) { 848 struct loader_device *next_dev = dev->next; 849 loader_destroy_logical_device(dev); 850 dev = next_dev; 851 } 852 853 free(icd); 854} 855 856static struct loader_icd * loader_icd_create(const struct loader_scanned_icds *scanned) 857{ 858 struct loader_icd *icd; 859 860 icd = malloc(sizeof(*icd)); 861 if (!icd) 862 return NULL; 863 864 memset(icd, 0, sizeof(*icd)); 865 866 icd->scanned_icds = scanned; 867 868 return icd; 869} 870 871static struct loader_icd *loader_icd_add( 872 struct loader_instance *ptr_inst, 873 const struct loader_scanned_icds *scanned) 874{ 875 struct loader_icd *icd; 876 877 icd = loader_icd_create(scanned); 878 if (!icd) 879 return NULL; 880 881 /* prepend to the list */ 882 icd->next = ptr_inst->icds; 883 ptr_inst->icds = icd; 884 ptr_inst->total_icd_count++; 885 886 return icd; 887} 888 889static void loader_scanned_icd_add(const char *filename) 890{ 891 loader_platform_dl_handle handle; 892 PFN_vkCreateInstance fp_create_inst; 893 PFN_vkGetGlobalExtensionProperties fp_get_global_ext_props; 894 PFN_vkGetInstanceProcAddr fp_get_proc_addr; 895 struct loader_scanned_icds *new_node; 896 897 // Used to call: dlopen(filename, RTLD_LAZY); 898 handle = loader_platform_open_library(filename); 899 if (!handle) { 900 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_open_library_error(filename)); 901 return; 902 } 903 904#define LOOKUP_LD(func_ptr, func) do { \ 905 func_ptr = (PFN_vk ##func) loader_platform_get_proc_address(handle, "vk" #func); \ 906 if (!func_ptr) { \ 907 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_get_proc_address_error("vk" #func)); \ 908 return; \ 909 } \ 910} while (0) 911 912 LOOKUP_LD(fp_get_proc_addr, GetInstanceProcAddr); 913 LOOKUP_LD(fp_create_inst, CreateInstance); 914 LOOKUP_LD(fp_get_global_ext_props, GetGlobalExtensionProperties); 915 916#undef LOOKUP_LD 917 918 new_node = (struct loader_scanned_icds *) malloc(sizeof(struct loader_scanned_icds) 919 + strlen(filename) + 1); 920 if (!new_node) { 921 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd"); 922 return; 923 } 924 925 new_node->handle = handle; 926 new_node->GetInstanceProcAddr = fp_get_proc_addr; 927 new_node->CreateInstance = fp_create_inst; 928 new_node->GetGlobalExtensionProperties = fp_get_global_ext_props; 929 loader_init_ext_list(&new_node->global_extension_list); 930 loader_init_ext_list(&new_node->device_extension_list); 931 new_node->next = loader.scanned_icd_list; 932 933 new_node->lib_name = (char *) (new_node + 1); 934 if (!new_node->lib_name) { 935 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd"); 936 return; 937 } 938 strcpy(new_node->lib_name, filename); 939 940 loader.scanned_icd_list = new_node; 941 942 loader_add_global_extensions( 943 (PFN_vkGetGlobalExtensionProperties) fp_get_global_ext_props, 944 new_node->lib_name, 945 handle, 946 VK_EXTENSION_ORIGIN_ICD, 947 &new_node->global_extension_list); 948} 949 950static struct loader_extension_list *loader_global_extensions(const char *pLayerName) 951{ 952 if (pLayerName == NULL || (strlen(pLayerName) == 0)) { 953 return &loader.global_extensions; 954 } 955 956 /* Find and return global extension list for given layer */ 957 for (uint32_t i = 0; i < loader.scanned_instance_layers.count; i++) { 958 struct loader_layer_properties *props = &loader.scanned_instance_layers.list[i]; 959 if (strcmp(props->info.layerName, pLayerName) == 0) { 960 return &props->instance_extension_list; 961 } 962 } 963 964 return NULL; 965} 966 967 968static void loader_physical_device_extensions( 969 struct loader_icd *icd, 970 uint32_t gpu_idx, 971 const char *layer_name, 972 uint32_t *count, 973 struct loader_extension_list **list) 974{ 975 *count = 0; 976 if (layer_name == NULL || (strlen(layer_name) == 0)) { 977 *count = icd->device_extension_cache[gpu_idx].count; 978 *list = &icd->device_extension_cache[gpu_idx]; 979 return; 980 } 981 for (uint32_t i = 0; i < loader.scanned_device_layers.count; i++) { 982 struct loader_layer_properties *props = &(loader.scanned_device_layers.list[i]); 983 if ((strcmp(layer_name, props->info.layerName) == 0)) { 984 *count = props->device_extension_list.count; 985 *list = &props->device_extension_list; 986 break; 987 } 988 } 989} 990 991static bool loader_icd_init_entrys(struct loader_icd *icd, 992 VkInstance inst, 993 const PFN_vkGetInstanceProcAddr fp_gipa) 994{ 995 /* initialize entrypoint function pointers */ 996 997 #define LOOKUP_GIPA(func, required) do { \ 998 icd->func = (PFN_vk ##func) fp_gipa(inst, "vk" #func); \ 999 if (!icd->func && required) { \ 1000 loader_log(VK_DBG_REPORT_WARN_BIT, 0, \ 1001 loader_platform_get_proc_address_error("vk" #func)); \ 1002 return false; \ 1003 } \ 1004 } while (0) 1005 1006 LOOKUP_GIPA(GetDeviceProcAddr, true); 1007 LOOKUP_GIPA(DestroyInstance, true); 1008 LOOKUP_GIPA(EnumeratePhysicalDevices, true); 1009 LOOKUP_GIPA(GetPhysicalDeviceFeatures, true); 1010 LOOKUP_GIPA(GetPhysicalDeviceFormatProperties, true); 1011 LOOKUP_GIPA(GetPhysicalDeviceImageFormatProperties, true); 1012 LOOKUP_GIPA(GetPhysicalDeviceLimits, true); 1013 LOOKUP_GIPA(CreateDevice, true); 1014 LOOKUP_GIPA(GetPhysicalDeviceProperties, true); 1015 LOOKUP_GIPA(GetPhysicalDeviceMemoryProperties, true); 1016 LOOKUP_GIPA(GetPhysicalDeviceQueueCount, true); 1017 LOOKUP_GIPA(GetPhysicalDeviceQueueProperties, true); 1018 LOOKUP_GIPA(GetPhysicalDeviceExtensionProperties, true); 1019 LOOKUP_GIPA(GetPhysicalDeviceSparseImageFormatProperties, true); 1020 LOOKUP_GIPA(DbgCreateMsgCallback, false); 1021 LOOKUP_GIPA(DbgDestroyMsgCallback, false); 1022 LOOKUP_GIPA(GetPhysicalDeviceSurfaceSupportWSI, false); 1023 1024#undef LOOKUP_GIPA 1025 1026 return true; 1027} 1028 1029static void loader_debug_init(void) 1030{ 1031 const char *env; 1032 1033 if (g_loader_debug > 0) 1034 return; 1035 1036 g_loader_debug = 0; 1037 1038 /* parse comma-separated debug options */ 1039 env = getenv("VK_LOADER_DEBUG"); 1040 while (env) { 1041 const char *p = strchr(env, ','); 1042 size_t len; 1043 1044 if (p) 1045 len = p - env; 1046 else 1047 len = strlen(env); 1048 1049 if (len > 0) { 1050 if (strncmp(env, "warn", len) == 0) { 1051 g_loader_debug |= LOADER_WARN_BIT; 1052 g_loader_log_msgs |= VK_DBG_REPORT_WARN_BIT; 1053 } else if (strncmp(env, "info", len) == 0) { 1054 g_loader_debug |= LOADER_INFO_BIT; 1055 g_loader_log_msgs |= VK_DBG_REPORT_INFO_BIT; 1056 } else if (strncmp(env, "perf", len) == 0) { 1057 g_loader_debug |= LOADER_PERF_BIT; 1058 g_loader_log_msgs |= VK_DBG_REPORT_PERF_WARN_BIT; 1059 } else if (strncmp(env, "error", len) == 0) { 1060 g_loader_debug |= LOADER_ERROR_BIT; 1061 g_loader_log_msgs |= VK_DBG_REPORT_ERROR_BIT; 1062 } else if (strncmp(env, "debug", len) == 0) { 1063 g_loader_debug |= LOADER_DEBUG_BIT; 1064 g_loader_log_msgs |= VK_DBG_REPORT_DEBUG_BIT; 1065 } 1066 } 1067 1068 if (!p) 1069 break; 1070 1071 env = p + 1; 1072 } 1073} 1074 1075struct loader_manifest_files { 1076 uint32_t count; 1077 char **filename_list; 1078}; 1079 1080/** 1081 * Get next file or dirname given a string list or registry key path 1082 * 1083 * \returns 1084 * A pointer to first char in the next path. 1085 * The next path (or NULL) in the list is returned in next_path. 1086 * Note: input string is modified in some cases. PASS IN A COPY! 1087 */ 1088static char *loader_get_next_path(char *path) 1089{ 1090 uint32_t len; 1091 char *next; 1092 1093 if (path == NULL) 1094 return NULL; 1095 next = strchr(path, PATH_SEPERATOR); 1096 if (next == NULL) { 1097 len = (uint32_t) strlen(path); 1098 next = path + len; 1099 } 1100 else { 1101 *next = '\0'; 1102 next++; 1103 } 1104 1105 return next; 1106} 1107 1108/** 1109 * Given a path which is absolute or relative. Expand the path if relative otherwise 1110 * leave the path unmodified if absolute. The path which is relative from is 1111 * given in rel_base and should include trailing directory seperator '/' 1112 * 1113 * \returns 1114 * A string in out_fullpath of the full absolute path 1115 * Side effect is that dir string maybe modified. 1116 */ 1117static void loader_expand_path(const char *path, 1118 const char *rel_base, 1119 size_t out_size, 1120 char *out_fullpath) 1121{ 1122 if (loader_platform_is_path_absolute(path)) { 1123 strncpy(out_fullpath, path, out_size); 1124 out_fullpath[out_size - 1] = '\0'; 1125 } 1126 else { 1127 // convert relative to absolute path based on rel_base 1128 size_t len = strlen(path); 1129 strncpy(out_fullpath, rel_base, out_size); 1130 out_fullpath[out_size - 1] = '\0'; 1131 assert(out_size >= strlen(out_fullpath) + len + 1); 1132 strncat(out_fullpath, path, len); 1133 } 1134} 1135 1136/** 1137 * Given a filename (file) and a list of paths (dir), try to find an existing 1138 * file in the paths. If filename already is a path then no 1139 * searching in the given paths. 1140 * 1141 * \returns 1142 * A string in out_fullpath of either the full path or file. 1143 * Side effect is that dir string maybe modified. 1144 */ 1145static void loader_get_fullpath(const char *file, 1146 char *dir, 1147 size_t out_size, 1148 char *out_fullpath) 1149{ 1150 char *next_dir; 1151 if (strchr(file,DIRECTORY_SYMBOL) == NULL) { 1152 //find file exists with prepending given path 1153 while (*dir) { 1154 next_dir = loader_get_next_path(dir); 1155 snprintf(out_fullpath, out_size, "%s%c%s", 1156 dir, DIRECTORY_SYMBOL, file); 1157 if (loader_platform_file_exists(out_fullpath)) { 1158 return; 1159 } 1160 dir = next_dir; 1161 } 1162 } 1163 snprintf(out_fullpath, out_size, "%s", file); 1164} 1165 1166/** 1167 * Read a JSON file into a buffer. 1168 * 1169 * \returns 1170 * A pointer to a cJSON object representing the JSON parse tree. 1171 * This returned buffer should be freed by caller. 1172 */ 1173static cJSON *loader_get_json(const char *filename) 1174{ 1175 FILE *file; 1176 char *json_buf; 1177 cJSON *json; 1178 uint64_t len; 1179 file = fopen(filename,"rb"); 1180 fseek(file, 0, SEEK_END); 1181 len = ftell(file); 1182 fseek(file, 0, SEEK_SET); 1183 json_buf = (char*) loader_stack_alloc(len+1); 1184 if (json_buf == NULL) { 1185 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get JSON file"); 1186 fclose(file); 1187 return NULL; 1188 } 1189 if (fread(json_buf, sizeof(char), len, file) != len) { 1190 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "fread failed can't get JSON file"); 1191 fclose(file); 1192 return NULL; 1193 } 1194 fclose(file); 1195 json_buf[len] = '\0'; 1196 1197 //parse text from file 1198 json = cJSON_Parse(json_buf); 1199 if (json == NULL) 1200 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Can't parse JSON file %s", filename); 1201 return json; 1202} 1203 1204/** 1205 * Given a cJSON struct (json) of the top level JSON object from layer manifest 1206 * file, add entry to the layer_list. 1207 * Fill out the layer_properties in this list entry from the input cHJSON object. 1208 * 1209 * \returns 1210 * void 1211 * layer_list has a new entry and initialized accordingly. 1212 * If the json input object does not have all the required fields no entry 1213 * is added to the list. 1214 */ 1215static void loader_add_layer_properties(struct loader_layer_list *layer_instance_list, 1216 struct loader_layer_list *layer_device_list, 1217 cJSON *json, 1218 bool is_implicit, 1219 char *filename) 1220{ 1221 /* Fields in layer manifest file that are required: 1222 * (required) “file_format_version” 1223 * following are required in the "layer" object: 1224 * (required) "name" 1225 * (required) "type" 1226 * (required) “library_path” 1227 * (required) “abi_versions” 1228 * (required) “implementation_version” 1229 * (required) “description” 1230 * (required for implicit layers) “disable_environment” 1231 * 1232 * First get all required items and if any missing abort 1233 */ 1234 1235 struct loader_layer_list *layer_list; 1236 cJSON *item, *layer_node, *ext_item; 1237 char *temp; 1238 char *name, *type, *library_path, *abi_versions; 1239 char *implementation_version, *description; 1240 cJSON *disable_environment; 1241 int i; 1242 struct loader_extension_property ext_prop; 1243 item = cJSON_GetObjectItem(json, "file_format_version"); 1244 if (item == NULL) { 1245 return; 1246 } 1247 char *file_vers = cJSON_PrintUnformatted(item); 1248 loader_log(VK_DBG_REPORT_INFO_BIT, 0, "Found manifest file %s, version %s", 1249 filename, file_vers); 1250 if (strcmp(file_vers, "\"0.9.0\"") != 0) 1251 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Unexpected manifest file version (expected 1.0.0), may cause errors"); 1252 free(file_vers); 1253 1254 //TODO handle freeing the allocations: disable_env , enable_env, GIPA, GDPA, library_path 1255 //TODO handle multiple layer nodes in the file 1256 //TODO handle scanned libraries not one per layer property 1257 layer_node = cJSON_GetObjectItem(json, "layer"); 1258 if (layer_node == NULL) { 1259 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"layer\" object in manifest JSON file, skipping"); 1260 return; 1261 } 1262#define GET_JSON_OBJECT(node, var) { \ 1263 var = cJSON_GetObjectItem(node, #var); \ 1264 if (var == NULL) \ 1265 return; \ 1266 } 1267#define GET_JSON_ITEM(node, var) { \ 1268 item = cJSON_GetObjectItem(node, #var); \ 1269 if (item == NULL) \ 1270 return; \ 1271 temp = cJSON_Print(item); \ 1272 temp[strlen(temp) - 1] = '\0'; \ 1273 var = malloc(strlen(temp) + 1); \ 1274 strcpy(var, &temp[1]); \ 1275 free(temp); \ 1276 } 1277 GET_JSON_ITEM(layer_node, name) 1278 GET_JSON_ITEM(layer_node, type) 1279 GET_JSON_ITEM(layer_node, library_path) 1280 GET_JSON_ITEM(layer_node, abi_versions) 1281 GET_JSON_ITEM(layer_node, implementation_version) 1282 GET_JSON_ITEM(layer_node, description) 1283 if (is_implicit) { 1284 GET_JSON_OBJECT(layer_node, disable_environment) 1285 } 1286#undef GET_JSON_ITEM 1287#undef GET_JSON_OBJECT 1288 1289 //TODO move layer_XXXX_list capacity check into this spot so know what type it is 1290 assert((layer_instance_list->count + 1) * sizeof(struct loader_layer_properties) <= layer_instance_list->capacity); 1291 assert((layer_device_list->count + 1) * sizeof(struct loader_layer_properties) <= layer_device_list->capacity); 1292 1293 // add list entry 1294 struct loader_layer_properties *props; 1295 if (!strcmp(type, "DEVICE")) { 1296 layer_list = layer_device_list; 1297 props = &(layer_list->list[layer_list->count]); 1298 props->type = (is_implicit) ? VK_LAYER_TYPE_DEVICE_IMPLICIT : VK_LAYER_TYPE_DEVICE_EXPLICIT; 1299 } 1300 if (!strcmp(type, "INSTANCE")) { 1301 layer_list = layer_instance_list; 1302 props = &(layer_list->list[layer_list->count]); 1303 props->type = (is_implicit) ? VK_LAYER_TYPE_INSTANCE_IMPLICIT : VK_LAYER_TYPE_INSTANCE_EXPLICIT; 1304 layer_list = layer_instance_list; 1305 } 1306 if (!strcmp(type, "GLOBAL")) { 1307 layer_list = layer_instance_list; 1308 props = &(layer_list->list[layer_list->count]); 1309 props->type = (is_implicit) ? VK_LAYER_TYPE_GLOBAL_IMPLICIT : VK_LAYER_TYPE_GLOBAL_EXPLICIT; 1310 } 1311 free(type); 1312 1313 strncpy(props->info.layerName, name, sizeof(props->info.layerName)); 1314 props->info.layerName[sizeof(props->info.layerName) - 1] = '\0'; 1315 free(name); 1316 1317 char *fullpath = malloc(2048); 1318 char *rel_base; 1319 if (strchr(library_path, DIRECTORY_SYMBOL) == NULL) { 1320 // a filename which is assumed in the system directory 1321 char *def_path = loader_stack_alloc(strlen(DEFAULT_VK_LAYERS_PATH) + 1); 1322 strcpy(def_path, DEFAULT_VK_LAYERS_PATH); 1323 loader_get_fullpath(library_path, def_path, 2048, fullpath); 1324 } 1325 else { 1326 // a relative or absolute path 1327 char *name_copy = loader_stack_alloc(strlen(filename) + 2); 1328 size_t len; 1329 strcpy(name_copy, filename); 1330 rel_base = loader_platform_dirname(name_copy); 1331 len = strlen(rel_base); 1332 rel_base[len] = DIRECTORY_SYMBOL; 1333 rel_base[len + 1] = '\0'; 1334 loader_expand_path(library_path, rel_base, 2048, fullpath); 1335 } 1336 props->lib_info.lib_name = fullpath; 1337 props->info.specVersion = loader_make_version(abi_versions); 1338 props->info.implVersion = loader_make_version(implementation_version); 1339 free(abi_versions); 1340 free(implementation_version); 1341 strncpy((char *) props->info.description, description, sizeof(props->info.description)); 1342 props->info.description[sizeof(props->info.description) - 1] = '\0'; 1343 free(description); 1344 if (is_implicit) { 1345 props->disable_env_var.name = disable_environment->child->string; 1346 props->disable_env_var.value = disable_environment->child->valuestring; 1347 } 1348 layer_list->count++; 1349 1350 /** 1351 * Now get all optional items and objects and put in list: 1352 * functions 1353 * instance_extensions 1354 * device_extensions 1355 * enable_environment (implicit layers only) 1356 */ 1357#define GET_JSON_OBJECT(node, var) { \ 1358 var = cJSON_GetObjectItem(node, #var); \ 1359 } 1360#define GET_JSON_ITEM(node, var) { \ 1361 item = cJSON_GetObjectItem(node, #var); \ 1362 if (item != NULL) \ 1363 temp = cJSON_Print(item); \ 1364 temp[strlen(temp) - 1] = '\0'; \ 1365 var = malloc(strlen(temp) + 1); \ 1366 strcpy(var, &temp[1]); \ 1367 free(temp); \ 1368 } 1369 1370 cJSON *instance_extensions, *device_extensions, *functions, *enable_environment; 1371 char *vkGetInstanceProcAddr, *vkGetDeviceProcAddr, *version; 1372 GET_JSON_OBJECT(layer_node, functions) 1373 if (functions != NULL) { 1374 GET_JSON_ITEM(functions, vkGetInstanceProcAddr) 1375 GET_JSON_ITEM(functions, vkGetDeviceProcAddr) 1376 props->functions.str_gipa = vkGetInstanceProcAddr; 1377 props->functions.str_gdpa = vkGetDeviceProcAddr; 1378 } 1379 GET_JSON_OBJECT(layer_node, instance_extensions) 1380 if (instance_extensions != NULL) { 1381 int count = cJSON_GetArraySize(instance_extensions); 1382 for (i = 0; i < count; i++) { 1383 ext_item = cJSON_GetArrayItem(instance_extensions, i); 1384 GET_JSON_ITEM(ext_item, name) 1385 GET_JSON_ITEM(ext_item, version) 1386 ext_prop.origin = VK_EXTENSION_ORIGIN_LAYER; 1387 ext_prop.lib_name = library_path; 1388 strcpy(ext_prop.info.extName, name); 1389 ext_prop.info.specVersion = loader_make_version(version); 1390 free(version); 1391 free(name); 1392 loader_add_to_ext_list(&props->instance_extension_list, 1, &ext_prop); 1393 } 1394 } 1395 GET_JSON_OBJECT(layer_node, device_extensions) 1396 if (device_extensions != NULL) { 1397 int count = cJSON_GetArraySize(device_extensions); 1398 for (i = 0; i < count; i++) { 1399 ext_item = cJSON_GetArrayItem(device_extensions, i); 1400 GET_JSON_ITEM(ext_item, name); 1401 GET_JSON_ITEM(ext_item, version); 1402 ext_prop.origin = VK_EXTENSION_ORIGIN_LAYER; 1403 ext_prop.lib_name = library_path; 1404 strcpy(ext_prop.info.extName, name); 1405 ext_prop.info.specVersion = loader_make_version(version); 1406 free(version); 1407 free(name); 1408 loader_add_to_ext_list(&props->device_extension_list, 1, &ext_prop); 1409 } 1410 } 1411 if (is_implicit) { 1412 GET_JSON_OBJECT(layer_node, enable_environment) 1413 props->enable_env_var.name = enable_environment->child->string; 1414 props->enable_env_var.value = enable_environment->child->valuestring; 1415 } 1416#undef GET_JSON_ITEM 1417#undef GET_JSON_OBJECT 1418 // for global layers need to add them to both device and instance list 1419 if (props->type & (VK_LAYER_TYPE_GLOBAL_IMPLICIT | VK_LAYER_TYPE_GLOBAL_EXPLICIT)) { 1420 //copy into device layer list 1421 memcpy(&(layer_device_list->list[layer_device_list->count++]), props, sizeof(*props)); 1422 } 1423 1424} 1425 1426/** 1427 * Find the Vulkan library manifest files. 1428 * 1429 * This function scans the location or env_override directories/files 1430 * for a list of JSON manifest files. If env_override is non-NULL 1431 * and has a valid value. Then the location is ignored. Otherwise 1432 * location is used to look for manifest files. The location 1433 * is interpreted as Registry path on Windows and a directory path(s) 1434 * on Linux. 1435 * 1436 * \returns 1437 * A string list of manifest files to be opened in out_files param. 1438 * List has a pointer to string for each manifest filename. 1439 * When done using the list in out_files, pointers should be freed. 1440 * Location or override string lists can be either files or directories as follows: 1441 * | location | override 1442 * -------------------------------- 1443 * Win ICD | files | files 1444 * Win Layer | files | dirs 1445 * Linux ICD | dirs | files 1446 * Linux Layer| dirs | dirs 1447 */ 1448static void loader_get_manifest_files(const char *env_override, 1449 bool is_layer, 1450 const char *location, 1451 struct loader_manifest_files *out_files) 1452{ 1453 char *override = NULL; 1454 char *loc; 1455 char *file, *next_file, *name; 1456 size_t alloced_count = 64; 1457 char full_path[2048]; 1458 DIR *sysdir = NULL; 1459 bool list_is_dirs = false; 1460 struct dirent *dent; 1461 1462 out_files->count = 0; 1463 out_files->filename_list = NULL; 1464 1465 if (env_override != NULL && (override = getenv(env_override))) { 1466#if defined(__linux__) 1467 if (geteuid() != getuid()) { 1468 /* Don't allow setuid apps to use the env var: */ 1469 override = NULL; 1470 } 1471#endif 1472 } 1473 1474 if (location == NULL) { 1475 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, 1476 "Can't get manifest files with NULL location, env_override=%s", 1477 env_override); 1478 return; 1479 } 1480 1481#if defined(__linux__) 1482 list_is_dirs = (override == NULL || is_layer) ? true : false; 1483#else //WIN32 1484 list_is_dirs = (is_layer && override != NULL) ? true : false; 1485#endif 1486 // Make a copy of the input we are using so it is not modified 1487 // Also handle getting the location(s) from registry on Windows 1488 if (override == NULL) { 1489 loc = loader_stack_alloc(strlen(location) + 1); 1490 if (loc == NULL) { 1491 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files"); 1492 return; 1493 } 1494 strcpy(loc, location); 1495#if defined (_WIN32) 1496 loc = loader_get_registry_files(loc); 1497 if (loc == NULL) { 1498 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Registry lookup failed can't get manifest files"); 1499 return; 1500 } 1501#endif 1502 } 1503 else { 1504 loc = loader_stack_alloc(strlen(override) + 1); 1505 if (loc == NULL) { 1506 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files"); 1507 return; 1508 } 1509 strcpy(loc, override); 1510 } 1511 1512 // Print out the paths being searched if debugging is enabled 1513 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "Searching the following paths for manifest files: %s\n", loc); 1514 1515 file = loc; 1516 while (*file) { 1517 next_file = loader_get_next_path(file); 1518 if (list_is_dirs) { 1519 sysdir = opendir(file); 1520 name = NULL; 1521 if (sysdir) { 1522 dent = readdir(sysdir); 1523 if (dent == NULL) 1524 break; 1525 name = &(dent->d_name[0]); 1526 loader_get_fullpath(name, file, sizeof(full_path), full_path); 1527 name = full_path; 1528 } 1529 } 1530 else { 1531#if defined(__linux__) 1532 // only Linux has relative paths 1533 char *dir; 1534 // make a copy of location so it isn't modified 1535 dir = alloca(strlen(location) + 1); 1536 if (dir == NULL) { 1537 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files"); 1538 return; 1539 } 1540 strcpy(dir, location); 1541 1542 loader_get_fullpath(file, dir, sizeof(full_path), full_path); 1543 1544 name = full_path; 1545#else // WIN32 1546 name = file; 1547#endif 1548 } 1549 while (name) { 1550 /* Look for files ending with ".json" suffix */ 1551 uint32_t nlen = (uint32_t) strlen(name); 1552 const char *suf = name + nlen - 5; 1553 if ((nlen > 5) && !strncmp(suf, ".json", 5)) { 1554 if (out_files->count == 0) { 1555 out_files->filename_list = malloc(alloced_count * sizeof(char *)); 1556 } 1557 else if (out_files->count == alloced_count) { 1558 out_files->filename_list = realloc(out_files->filename_list, 1559 alloced_count * sizeof(char *) * 2); 1560 alloced_count *= 2; 1561 } 1562 if (out_files->filename_list == NULL) { 1563 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't alloc manifest file list"); 1564 return; 1565 } 1566 out_files->filename_list[out_files->count] = malloc(strlen(name) + 1); 1567 if (out_files->filename_list[out_files->count] == NULL) { 1568 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files"); 1569 return; 1570 } 1571 strcpy(out_files->filename_list[out_files->count], name); 1572 out_files->count++; 1573 } else if (!list_is_dirs) { 1574 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Skipping manifest file %s, file name must end in .json", name); 1575 } 1576 if (list_is_dirs) { 1577 dent = readdir(sysdir); 1578 if (dent == NULL) 1579 break; 1580 name = &(dent->d_name[0]); 1581 loader_get_fullpath(name, file, sizeof(full_path), full_path); 1582 name = full_path; 1583 } 1584 else { 1585 break; 1586 } 1587 } 1588 if (sysdir) 1589 closedir(sysdir); 1590 file = next_file; 1591 } 1592 return; 1593} 1594 1595/** 1596 * Try to find the Vulkan ICD driver(s). 1597 * 1598 * This function scans the default system loader path(s) or path 1599 * specified by the \c VK_ICD_FILENAMES environment variable in 1600 * order to find loadable VK ICDs manifest files. From these 1601 * manifest files it finds the ICD libraries. 1602 * 1603 * \returns 1604 * void 1605 */ 1606void loader_icd_scan(void) 1607{ 1608 char *file_str; 1609 struct loader_manifest_files manifest_files; 1610 1611 1612 // convenient place to initialize a mutex 1613 loader_platform_thread_create_mutex(&loader_lock); 1614 1615 // convenient place to initialize logging 1616 loader_debug_init(); 1617 1618 // Get a list of manifest files for ICDs 1619 loader_get_manifest_files("VK_ICD_FILENAMES", false, DEFAULT_VK_DRIVERS_INFO, 1620 &manifest_files); 1621 if (manifest_files.count == 0) 1622 return; 1623 for (uint32_t i = 0; i < manifest_files.count; i++) { 1624 file_str = manifest_files.filename_list[i]; 1625 if (file_str == NULL) 1626 continue; 1627 1628 cJSON *json; 1629 json = loader_get_json(file_str); 1630 cJSON *item; 1631 item = cJSON_GetObjectItem(json, "file_format_version"); 1632 if (item == NULL) 1633 return; 1634 char *file_vers = cJSON_Print(item); 1635 loader_log(VK_DBG_REPORT_INFO_BIT, 0, "Found manifest file %s, version %s", 1636 file_str, file_vers); 1637 if (strcmp(file_vers, "\"1.0.0\"") != 0) 1638 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Unexpected manifest file version (expected 1.0.0), may cause errors"); 1639 free(file_vers); 1640 item = cJSON_GetObjectItem(json, "ICD"); 1641 if (item != NULL) { 1642 item = cJSON_GetObjectItem(item, "library_path"); 1643 if (item != NULL) { 1644 char *icd_filename = cJSON_PrintUnformatted(item); 1645 char *icd_file = icd_filename; 1646 if (icd_filename != NULL) { 1647 char def_dir[] = DEFAULT_VK_DRIVERS_PATH; 1648 char *dir = def_dir; 1649 1650 // Print out the paths being searched if debugging is enabled 1651 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "Searching for ICD drivers named %s at %s\n", icd_file, dir); 1652 1653 // strip off extra quotes 1654 if (icd_filename[strlen(icd_filename) - 1] == '"') 1655 icd_filename[strlen(icd_filename) - 1] = '\0'; 1656 if (icd_filename[0] == '"') 1657 icd_filename++; 1658#if defined(__linux__) 1659 char full_path[2048]; 1660 loader_get_fullpath(icd_filename, dir, sizeof(full_path), full_path); 1661 loader_scanned_icd_add(full_path); 1662#else // WIN32 1663 loader_scanned_icd_add(icd_filename); 1664#endif 1665 free(icd_file); 1666 } 1667 } 1668 else 1669 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"library_path\" in ICD JSON file %s, skipping", file_str); 1670 } 1671 else 1672 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"ICD\" object in ICD JSON file %s, skipping", file_str); 1673 1674 free(file_str); 1675 cJSON_Delete(json); 1676 } 1677 free(manifest_files.filename_list); 1678 1679} 1680 1681 1682void loader_layer_scan(void) 1683{ 1684 char *file_str; 1685 struct loader_manifest_files manifest_files; 1686 cJSON *json; 1687 uint32_t i; 1688 1689 // Get a list of manifest files for layers 1690 loader_get_manifest_files(LAYERS_PATH_ENV, true, DEFAULT_VK_LAYERS_INFO, 1691 &manifest_files); 1692 if (manifest_files.count == 0) 1693 return; 1694 1695#if 0 1696 /** 1697 * We need a list of the layer libraries, not just a list of 1698 * the layer properties (a layer library could expose more than 1699 * one layer property). This list of scanned layers would be 1700 * used to check for global and physicaldevice layer properties. 1701 */ 1702 if (!loader_init_layer_library_list(&loader.scanned_layer_libraries)) { 1703 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, 1704 "Malloc for layer list failed: %s line: %d", __FILE__, __LINE__); 1705 return; 1706 } 1707#endif 1708 1709 // TODO use global_layer add and delete functions instead 1710 if (loader.scanned_instance_layers.capacity == 0) { 1711 loader.scanned_instance_layers.list = malloc(sizeof(struct loader_layer_properties) * 64); 1712 if (loader.scanned_instance_layers.list == NULL) { 1713 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can'add any layer properties to list"); 1714 return; 1715 } 1716 memset(loader.scanned_instance_layers.list, 0, sizeof(struct loader_layer_properties) * 64); 1717 loader.scanned_instance_layers.capacity = sizeof(struct loader_layer_properties) * 64; 1718 } 1719 else { 1720 /* cleanup any previously scanned libraries */ 1721 //TODO make sure everything is cleaned up properly 1722 for (i = 0; i < loader.scanned_instance_layers.count; i++) { 1723 if (loader.scanned_instance_layers.list[i].lib_info.lib_name != NULL) 1724 free(loader.scanned_instance_layers.list[i].lib_info.lib_name); 1725 loader_destroy_ext_list(&loader.scanned_instance_layers.list[i].instance_extension_list); 1726 loader_destroy_ext_list(&loader.scanned_instance_layers.list[i].device_extension_list); 1727 loader.scanned_instance_layers.list[i].lib_info.lib_name = NULL; 1728 } 1729 loader.scanned_instance_layers.count = 0; 1730 } 1731 if (loader.scanned_device_layers.capacity == 0) { 1732 loader.scanned_device_layers.list = malloc(sizeof(struct loader_layer_properties) * 64); 1733 if (loader.scanned_device_layers.list == NULL) { 1734 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can'add any layer properties to list"); 1735 return; 1736 } 1737 memset(loader.scanned_device_layers.list, 0, sizeof(struct loader_layer_properties) * 64); 1738 loader.scanned_device_layers.capacity = sizeof(struct loader_layer_properties) * 64; 1739 } 1740 else { 1741 /* cleanup any previously scanned libraries */ 1742 //TODO make sure everything is cleaned up properly 1743 for (i = 0; i < loader.scanned_device_layers.count; i++) { 1744 if (loader.scanned_device_layers.list[i].lib_info.lib_name != NULL) 1745 free(loader.scanned_device_layers.list[i].lib_info.lib_name); 1746 loader_destroy_ext_list(&loader.scanned_device_layers.list[i].instance_extension_list); 1747 loader_destroy_ext_list(&loader.scanned_device_layers.list[i].device_extension_list); 1748 loader.scanned_device_layers.list[i].lib_info.lib_name = NULL; 1749 } 1750 loader.scanned_device_layers.count = 0; 1751 } 1752 1753 1754 for (i = 0; i < manifest_files.count; i++) { 1755 file_str = manifest_files.filename_list[i]; 1756 if (file_str == NULL) 1757 continue; 1758 1759 // parse file into JSON struct 1760 json = loader_get_json(file_str); 1761 if (!json) { 1762 continue; 1763 } 1764 // ensure enough room to add an entry 1765 if ((loader.scanned_instance_layers.count + 1) * sizeof (struct loader_layer_properties) 1766 > loader.scanned_instance_layers.capacity) { 1767 loader.scanned_instance_layers.list = realloc(loader.scanned_instance_layers.list, 1768 loader.scanned_instance_layers.capacity * 2); 1769 if (loader.scanned_instance_layers.list == NULL) { 1770 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, 1771 "realloc failed for scanned layers"); 1772 break; 1773 } 1774 loader.scanned_instance_layers.capacity *= 2; 1775 } 1776 // ensure enough room to add an entry 1777 if ((loader.scanned_device_layers.count + 1) * sizeof (struct loader_layer_properties) 1778 > loader.scanned_device_layers.capacity) { 1779 loader.scanned_device_layers.list = realloc(loader.scanned_device_layers.list, 1780 loader.scanned_device_layers.capacity * 2); 1781 if (loader.scanned_device_layers.list == NULL) { 1782 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, 1783 "realloc failed for scanned layers"); 1784 break; 1785 } 1786 loader.scanned_device_layers.capacity *= 2; 1787 } 1788 //TODO pass in implicit versus explicit bool 1789 //TODO error if device layers expose instance_extensions 1790 //TODO error if instance layers expose device extensions 1791 loader_add_layer_properties(&loader.scanned_instance_layers, 1792 &loader.scanned_device_layers, 1793 json, 1794 false, 1795 file_str); 1796 1797 1798 free(file_str); 1799 cJSON_Delete(json); 1800 } 1801 free(manifest_files.filename_list); 1802 1803} 1804 1805static PFN_vkVoidFunction VKAPI loader_gpa_instance_internal(VkInstance inst, const char * pName) 1806{ 1807 // inst is not wrapped 1808 if (inst == VK_NULL_HANDLE) { 1809 return NULL; 1810 } 1811 VkLayerInstanceDispatchTable* disp_table = * (VkLayerInstanceDispatchTable **) inst; 1812 void *addr; 1813 1814 if (!strcmp(pName, "vkGetInstanceProcAddr")) 1815 return (void *) loader_gpa_instance_internal; 1816 1817 if (disp_table == NULL) 1818 return NULL; 1819 1820 addr = loader_lookup_instance_dispatch_table(disp_table, pName); 1821 if (addr) { 1822 return addr; 1823 } 1824 1825 if (disp_table->GetInstanceProcAddr == NULL) { 1826 return NULL; 1827 } 1828 return disp_table->GetInstanceProcAddr(inst, pName); 1829} 1830 1831struct loader_icd * loader_get_icd(const VkPhysicalDevice gpu, uint32_t *gpu_index) 1832{ 1833 1834 *gpu_index = 0; 1835 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) { 1836 for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) { 1837 for (uint32_t i = 0; i < icd->gpu_count; i++) 1838 if (icd->gpus[i] == gpu) { 1839 *gpu_index = i; 1840 return icd; 1841 } 1842 } 1843 } 1844 return NULL; 1845} 1846 1847static loader_platform_dl_handle loader_add_layer_lib( 1848 const char *chain_type, 1849 struct loader_layer_properties *layer_prop) 1850{ 1851 struct loader_lib_info *new_layer_lib_list, *my_lib; 1852 1853 /* 1854 * TODO: We can now track this information in the 1855 * scanned_layer_libraries list. 1856 */ 1857 for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) { 1858 if (strcmp(loader.loaded_layer_lib_list[i].lib_name, layer_prop->lib_info.lib_name) == 0) { 1859 /* Have already loaded this library, just increment ref count */ 1860 loader.loaded_layer_lib_list[i].ref_count++; 1861 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, 1862 "%s Chain: Increment layer reference count for layer library %s", 1863 chain_type, layer_prop->lib_info.lib_name); 1864 return loader.loaded_layer_lib_list[i].lib_handle; 1865 } 1866 } 1867 1868 /* Haven't seen this library so load it */ 1869 new_layer_lib_list = realloc(loader.loaded_layer_lib_list, 1870 (loader.loaded_layer_lib_count + 1) * sizeof(struct loader_lib_info)); 1871 if (!new_layer_lib_list) { 1872 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed"); 1873 return NULL; 1874 } 1875 1876 my_lib = &new_layer_lib_list[loader.loaded_layer_lib_count]; 1877 1878 /* NOTE: We require that the layer property be immutable */ 1879 my_lib->lib_name = (char *) layer_prop->lib_info.lib_name; 1880 my_lib->ref_count = 0; 1881 my_lib->lib_handle = NULL; 1882 1883 if ((my_lib->lib_handle = loader_platform_open_library(my_lib->lib_name)) == NULL) { 1884 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, 1885 loader_platform_open_library_error(my_lib->lib_name)); 1886 return NULL; 1887 } else { 1888 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, 1889 "Chain: %s: Loading layer library %s", 1890 chain_type, layer_prop->lib_info.lib_name); 1891 } 1892 loader.loaded_layer_lib_count++; 1893 loader.loaded_layer_lib_list = new_layer_lib_list; 1894 my_lib->ref_count++; 1895 1896 return my_lib->lib_handle; 1897} 1898 1899static void loader_remove_layer_lib( 1900 struct loader_instance *inst, 1901 struct loader_layer_properties *layer_prop) 1902{ 1903 uint32_t idx; 1904 struct loader_lib_info *new_layer_lib_list, *my_lib = NULL; 1905 1906 for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) { 1907 if (strcmp(loader.loaded_layer_lib_list[i].lib_name, layer_prop->lib_info.lib_name) == 0) { 1908 /* found matching library */ 1909 idx = i; 1910 my_lib = &loader.loaded_layer_lib_list[i]; 1911 break; 1912 } 1913 } 1914 1915 if (my_lib) { 1916 my_lib->ref_count--; 1917 if (my_lib->ref_count > 0) { 1918 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, 1919 "Decrement reference count for layer library %s", layer_prop->lib_info.lib_name); 1920 return; 1921 } 1922 } 1923 loader_platform_close_library(my_lib->lib_handle); 1924 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, 1925 "Unloading layer library %s", layer_prop->lib_info.lib_name); 1926 1927 /* Need to remove unused library from list */ 1928 new_layer_lib_list = malloc((loader.loaded_layer_lib_count - 1) * sizeof(struct loader_lib_info)); 1929 if (!new_layer_lib_list) { 1930 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed"); 1931 return; 1932 } 1933 1934 if (idx > 0) { 1935 /* Copy records before idx */ 1936 memcpy(new_layer_lib_list, &loader.loaded_layer_lib_list[0], 1937 sizeof(struct loader_lib_info) * idx); 1938 } 1939 if (idx < (loader.loaded_layer_lib_count - 1)) { 1940 /* Copy records after idx */ 1941 memcpy(&new_layer_lib_list[idx], &loader.loaded_layer_lib_list[idx+1], 1942 sizeof(struct loader_lib_info) * (loader.loaded_layer_lib_count - idx - 1)); 1943 } 1944 1945 free(loader.loaded_layer_lib_list); 1946 loader.loaded_layer_lib_count--; 1947 loader.loaded_layer_lib_list = new_layer_lib_list; 1948} 1949 1950 1951/** 1952 * Go through the search_list and find any layers which match type. If layer 1953 * type match is found in then add it to ext_list. 1954 */ 1955//TODO need to handle implict layer enable env var and disable env var 1956static void loader_add_layer_implicit( 1957 const enum layer_type type, 1958 struct loader_layer_list *list, 1959 struct loader_layer_list *search_list) 1960{ 1961 uint32_t i; 1962 for (i = 0; i < search_list->count; i++) { 1963 const struct loader_layer_properties *prop = &search_list->list[i]; 1964 if (prop->type & type) { 1965 /* Found an layer with the same type, add to layer_list */ 1966 loader_add_to_layer_list(list, 1, prop); 1967 } 1968 } 1969 1970} 1971 1972/** 1973 * Get the layer name(s) from the env_name environment variable. If layer 1974 * is found in search_list then add it to layer_list. But only add it to 1975 * layer_list if type matches. 1976 */ 1977static void loader_add_layer_env( 1978 const enum layer_type type, 1979 const char *env_name, 1980 struct loader_layer_list *layer_list, 1981 const struct loader_layer_list *search_list) 1982{ 1983 char *layerEnv; 1984 char *next, *name; 1985 1986 layerEnv = getenv(env_name); 1987 if (layerEnv == NULL) { 1988 return; 1989 } 1990 name = loader_stack_alloc(strlen(layerEnv) + 1); 1991 if (name == NULL) { 1992 return; 1993 } 1994 strcpy(name, layerEnv); 1995 1996 while (name && *name ) { 1997 next = loader_get_next_path(name); 1998 loader_find_layer_name_add_list(name, type, search_list, layer_list); 1999 name = next; 2000 } 2001 2002 return; 2003} 2004 2005void loader_deactivate_instance_layers(struct loader_instance *instance) 2006{ 2007 if (!instance->activated_layer_list.count) { 2008 return; 2009 } 2010 2011 /* Create instance chain of enabled layers */ 2012 for (uint32_t i = 0; i < instance->activated_layer_list.count; i++) { 2013 struct loader_layer_properties *layer_prop = &instance->activated_layer_list.list[i]; 2014 2015 loader_remove_layer_lib(instance, layer_prop); 2016 } 2017 loader_destroy_layer_list(&instance->activated_layer_list); 2018} 2019 2020VkResult loader_enable_instance_layers( 2021 struct loader_instance *inst, 2022 const VkInstanceCreateInfo *pCreateInfo) 2023{ 2024 VkResult err; 2025 2026 if (inst == NULL) 2027 return VK_ERROR_UNKNOWN; 2028 2029 if (!loader_init_layer_list(&inst->activated_layer_list)) { 2030 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Instance activated layer list"); 2031 return VK_ERROR_OUT_OF_HOST_MEMORY; 2032 } 2033 2034 /* Add any implicit layers first */ 2035 loader_add_layer_implicit( 2036 VK_LAYER_TYPE_INSTANCE_IMPLICIT, 2037 &inst->activated_layer_list, 2038 &loader.scanned_instance_layers); 2039 2040 /* Add any layers specified via environment variable next */ 2041 loader_add_layer_env( 2042 VK_LAYER_TYPE_INSTANCE_EXPLICIT, 2043 "VK_INSTANCE_LAYERS", 2044 &inst->activated_layer_list, 2045 &loader.scanned_instance_layers); 2046 2047 /* Add layers specified by the application */ 2048 err = loader_add_layer_names_to_list( 2049 &inst->activated_layer_list, 2050 pCreateInfo->layerCount, 2051 pCreateInfo->ppEnabledLayerNames, 2052 &loader.scanned_instance_layers); 2053 2054 return err; 2055} 2056 2057uint32_t loader_activate_instance_layers(struct loader_instance *inst) 2058{ 2059 uint32_t layer_idx; 2060 VkBaseLayerObject *wrappedInstance; 2061 2062 if (inst == NULL) { 2063 return 0; 2064 } 2065 2066 // NOTE inst is unwrapped at this point in time 2067 void* baseObj = (void*) inst; 2068 void* nextObj = (void*) inst; 2069 VkBaseLayerObject *nextInstObj; 2070 PFN_vkGetInstanceProcAddr nextGPA = loader_gpa_instance_internal; 2071 2072 if (!inst->activated_layer_list.count) { 2073 return 0; 2074 } 2075 2076 wrappedInstance = loader_stack_alloc(sizeof(VkBaseLayerObject) 2077 * inst->activated_layer_list.count); 2078 if (!wrappedInstance) { 2079 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Instance objects for layer"); 2080 return 0; 2081 } 2082 2083 /* Create instance chain of enabled layers */ 2084 layer_idx = inst->activated_layer_list.count - 1; 2085 for (int32_t i = inst->activated_layer_list.count - 1; i >= 0; i--) { 2086 struct loader_layer_properties *layer_prop = &inst->activated_layer_list.list[i]; 2087 loader_platform_dl_handle lib_handle; 2088 2089 /* 2090 * Note: An extension's Get*ProcAddr should not return a function pointer for 2091 * any extension entry points until the extension has been enabled. 2092 * To do this requires a different behavior from Get*ProcAddr functions implemented 2093 * in layers. 2094 * The very first call to a layer will be it's Get*ProcAddr function requesting 2095 * the layer's vkGet*ProcAddr. The layer should intialize it's internal dispatch table 2096 * with the wrapped object given (either Instance or Device) and return the layer's 2097 * Get*ProcAddr function. The layer should also use this opportunity to record the 2098 * baseObject so that it can find the correct local dispatch table on future calls. 2099 * Subsequent calls to Get*ProcAddr, CreateInstance, CreateDevice 2100 * will not use a wrapped object and must look up their local dispatch table from 2101 * the given baseObject. 2102 */ 2103 nextInstObj = (wrappedInstance + layer_idx); 2104 nextInstObj->pGPA = (PFN_vkGPA) nextGPA; 2105 nextInstObj->baseObject = baseObj; 2106 nextInstObj->nextObject = nextObj; 2107 nextObj = (void*) nextInstObj; 2108 2109 char funcStr[256]; 2110 snprintf(funcStr, 256, "%sGetInstanceProcAddr", layer_prop->info.layerName); 2111 lib_handle = loader_add_layer_lib("instance", layer_prop); 2112 if ((nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL) 2113 nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr"); 2114 if (!nextGPA) { 2115 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to find vkGetInstanceProcAddr in layer %s", layer_prop->lib_info.lib_name); 2116 2117 /* TODO: Should we return nextObj, nextGPA to previous? */ 2118 continue; 2119 } 2120 2121 loader_log(VK_DBG_REPORT_INFO_BIT, 0, 2122 "Insert instance layer %s (%s)", 2123 layer_prop->info.layerName, 2124 layer_prop->lib_info.lib_name); 2125 2126 layer_idx--; 2127 } 2128 2129 loader_init_instance_core_dispatch_table(inst->disp, nextGPA, (VkInstance) nextObj, (VkInstance) baseObj); 2130 2131 return inst->activated_layer_list.count; 2132} 2133 2134void loader_activate_instance_layer_extensions(struct loader_instance *inst) 2135{ 2136 2137 loader_init_instance_extension_dispatch_table(inst->disp, 2138 inst->disp->GetInstanceProcAddr, 2139 (VkInstance) inst); 2140} 2141 2142static VkResult loader_enable_device_layers( 2143 struct loader_icd *icd, 2144 struct loader_device *dev, 2145 const VkDeviceCreateInfo *pCreateInfo) 2146{ 2147 VkResult err; 2148 2149 if (dev == NULL) 2150 return VK_ERROR_UNKNOWN; 2151 2152 if (dev->activated_layer_list.list == NULL || dev->activated_layer_list.capacity == 0) { 2153 loader_init_layer_list(&dev->activated_layer_list); 2154 } 2155 2156 if (dev->activated_layer_list.list == NULL) { 2157 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc device activated layer list"); 2158 return VK_ERROR_OUT_OF_HOST_MEMORY; 2159 } 2160 2161 /* Add any implicit layers first */ 2162 loader_add_layer_implicit( 2163 VK_LAYER_TYPE_DEVICE_IMPLICIT, 2164 &dev->activated_layer_list, 2165 &loader.scanned_device_layers); 2166 2167 /* Add any layers specified via environment variable next */ 2168 loader_add_layer_env( 2169 VK_LAYER_TYPE_DEVICE_EXPLICIT, 2170 "VK_DEVICE_LAYERS", 2171 &dev->activated_layer_list, 2172 &loader.scanned_device_layers); 2173 2174 /* Add layers specified by the application */ 2175 err = loader_add_layer_names_to_list( 2176 &dev->activated_layer_list, 2177 pCreateInfo->layerCount, 2178 pCreateInfo->ppEnabledLayerNames, 2179 &loader.scanned_device_layers); 2180 2181 return err; 2182} 2183 2184/* 2185 * This function terminates the device chain fro CreateDevice. 2186 * CreateDevice is a special case and so the loader call's 2187 * the ICD's CreateDevice before creating the chain. Since 2188 * we can't call CreateDevice twice we must terminate the 2189 * device chain with something else. 2190 */ 2191static VkResult VKAPI scratch_vkCreateDevice( 2192 VkPhysicalDevice gpu, 2193 const VkDeviceCreateInfo *pCreateInfo, 2194 VkDevice *pDevice) 2195{ 2196 return VK_SUCCESS; 2197} 2198 2199static PFN_vkVoidFunction VKAPI loader_GetDeviceChainProcAddr(VkDevice device, const char * name) 2200{ 2201 if (!strcmp(name, "vkGetDeviceProcAddr")) 2202 return (PFN_vkVoidFunction) loader_GetDeviceChainProcAddr; 2203 if (!strcmp(name, "vkCreateDevice")) 2204 return (PFN_vkVoidFunction) scratch_vkCreateDevice; 2205 2206 struct loader_device *found_dev; 2207 struct loader_icd *icd = loader_get_icd_and_device(device, &found_dev); 2208 return icd->GetDeviceProcAddr(device, name); 2209} 2210 2211static uint32_t loader_activate_device_layers( 2212 struct loader_icd *icd, 2213 struct loader_device *dev, 2214 VkDevice device) 2215{ 2216 if (!icd) 2217 return 0; 2218 2219 if (!dev) { 2220 return 0; 2221 } 2222 2223 /* activate any layer libraries */ 2224 void* nextObj = (void*) device; 2225 void* baseObj = nextObj; 2226 VkBaseLayerObject *nextGpuObj; 2227 PFN_vkGetDeviceProcAddr nextGPA = loader_GetDeviceChainProcAddr; 2228 VkBaseLayerObject *wrappedGpus; 2229 2230 if (!dev->activated_layer_list.count) 2231 return 0; 2232 2233 wrappedGpus = malloc(sizeof (VkBaseLayerObject) * dev->activated_layer_list.count); 2234 if (!wrappedGpus) { 2235 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Gpu objects for layer"); 2236 return 0; 2237 } 2238 2239 for (int32_t i = dev->activated_layer_list.count - 1; i >= 0; i--) { 2240 2241 struct loader_layer_properties *layer_prop = &dev->activated_layer_list.list[i]; 2242 loader_platform_dl_handle lib_handle; 2243 2244 nextGpuObj = (wrappedGpus + i); 2245 nextGpuObj->pGPA = (PFN_vkGPA)nextGPA; 2246 nextGpuObj->baseObject = baseObj; 2247 nextGpuObj->nextObject = nextObj; 2248 nextObj = (void*) nextGpuObj; 2249 2250 char funcStr[256]; 2251 snprintf(funcStr, 256, "%sGetDeviceProcAddr", layer_prop->info.layerName); 2252 lib_handle = loader_add_layer_lib("device", layer_prop); 2253 if ((nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL) 2254 nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetDeviceProcAddr"); 2255 if (!nextGPA) { 2256 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to find vkGetDeviceProcAddr in layer %s", layer_prop->info.layerName); 2257 continue; 2258 } 2259 2260 loader_log(VK_DBG_REPORT_INFO_BIT, 0, 2261 "Insert device layer library %s (%s)", 2262 layer_prop->info.layerName, 2263 layer_prop->lib_info.lib_name); 2264 2265 } 2266 2267 loader_init_device_dispatch_table(&dev->loader_dispatch, nextGPA, 2268 (VkDevice) nextObj, (VkDevice) baseObj); 2269 free(wrappedGpus); 2270 2271 return dev->activated_layer_list.count; 2272} 2273 2274VkResult loader_validate_layers( 2275 const uint32_t layer_count, 2276 const char * const *ppEnabledLayerNames, 2277 struct loader_layer_list *list) 2278{ 2279 struct loader_layer_properties *prop; 2280 2281 for (uint32_t i = 0; i < layer_count; i++) { 2282 prop = get_layer_property(ppEnabledLayerNames[i], 2283 list); 2284 if (!prop) { 2285 return VK_ERROR_INVALID_LAYER; 2286 } 2287 } 2288 2289 return VK_SUCCESS; 2290} 2291 2292VkResult loader_validate_instance_extensions( 2293 const VkInstanceCreateInfo *pCreateInfo) 2294{ 2295 struct loader_extension_property *extension_prop; 2296 struct loader_layer_properties *layer_prop; 2297 2298 for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) { 2299 extension_prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i], 2300 &loader.global_extensions); 2301 2302 if (extension_prop) { 2303 continue; 2304 } 2305 2306 extension_prop = NULL; 2307 2308 /* Not in global list, search layer extension lists */ 2309 for (uint32_t j = 0; j < pCreateInfo->layerCount; j++) { 2310 layer_prop = get_layer_property(pCreateInfo->ppEnabledLayerNames[i], 2311 &loader.scanned_instance_layers); 2312 2313 if (!layer_prop) { 2314 /* Should NOT get here, loader_validate_layers 2315 * should have already filtered this case out. 2316 */ 2317 continue; 2318 } 2319 2320 extension_prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i], 2321 &layer_prop->instance_extension_list); 2322 if (extension_prop) { 2323 /* Found the extension in one of the layers enabled by the app. */ 2324 break; 2325 } 2326 } 2327 2328 if (!extension_prop) { 2329 /* Didn't find extension name in any of the global layers, error out */ 2330 return VK_ERROR_INVALID_EXTENSION; 2331 } 2332 } 2333 return VK_SUCCESS; 2334} 2335 2336VkResult loader_validate_device_extensions( 2337 struct loader_icd *icd, 2338 uint32_t gpu_index, 2339 const VkDeviceCreateInfo *pCreateInfo) 2340{ 2341 struct loader_extension_property *extension_prop; 2342 struct loader_layer_properties *layer_prop; 2343 2344 for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) { 2345 const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i]; 2346 extension_prop = get_extension_property(extension_name, 2347 &icd->device_extension_cache[gpu_index]); 2348 2349 if (extension_prop) { 2350 continue; 2351 } 2352 2353 /* Not in global list, search layer extension lists */ 2354 for (uint32_t j = 0; j < pCreateInfo->layerCount; j++) { 2355 const char *layer_name = pCreateInfo->ppEnabledLayerNames[j]; 2356 layer_prop = get_layer_property(layer_name, 2357 &loader.scanned_device_layers); 2358 2359 if (!layer_prop) { 2360 /* Should NOT get here, loader_validate_instance_layers 2361 * should have already filtered this case out. 2362 */ 2363 continue; 2364 } 2365 2366 extension_prop = get_extension_property(extension_name, 2367 &layer_prop->device_extension_list); 2368 if (extension_prop) { 2369 /* Found the extension in one of the layers enabled by the app. */ 2370 break; 2371 } 2372 } 2373 2374 if (!extension_prop) { 2375 /* Didn't find extension name in any of the device layers, error out */ 2376 return VK_ERROR_INVALID_EXTENSION; 2377 } 2378 } 2379 return VK_SUCCESS; 2380} 2381 2382VkResult VKAPI loader_CreateInstance( 2383 const VkInstanceCreateInfo* pCreateInfo, 2384 VkInstance* pInstance) 2385{ 2386 struct loader_instance *ptr_instance = *(struct loader_instance **) pInstance; 2387 struct loader_scanned_icds *scanned_icds; 2388 struct loader_icd *icd; 2389 struct loader_extension_property *prop; 2390 char **filtered_extension_names = NULL; 2391 VkInstanceCreateInfo icd_create_info; 2392 VkResult res = VK_SUCCESS; 2393 bool success; 2394 2395 icd_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; 2396 icd_create_info.layerCount = 0; 2397 icd_create_info.ppEnabledLayerNames = NULL; 2398 icd_create_info.pAllocCb = pCreateInfo->pAllocCb; 2399 icd_create_info.pAppInfo = pCreateInfo->pAppInfo; 2400 icd_create_info.pNext = pCreateInfo->pNext; 2401 2402 /* 2403 * NOTE: Need to filter the extensions to only those 2404 * supported by the ICD. 2405 * No ICD will advertise support for layers. An ICD 2406 * library could support a layer, but it would be 2407 * independent of the actual ICD, just in the same library. 2408 */ 2409 filtered_extension_names = loader_stack_alloc(pCreateInfo->extensionCount * sizeof(char *)); 2410 if (!filtered_extension_names) { 2411 return VK_ERROR_OUT_OF_HOST_MEMORY; 2412 } 2413 icd_create_info.ppEnabledExtensionNames = (const char * const *) filtered_extension_names; 2414 2415 scanned_icds = loader.scanned_icd_list; 2416 while (scanned_icds) { 2417 icd = loader_icd_add(ptr_instance, scanned_icds); 2418 if (icd) { 2419 icd_create_info.extensionCount = 0; 2420 for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) { 2421 prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i], 2422 &scanned_icds->global_extension_list); 2423 if (prop) { 2424 filtered_extension_names[icd_create_info.extensionCount] = (char *) pCreateInfo->ppEnabledExtensionNames[i]; 2425 icd_create_info.extensionCount++; 2426 } 2427 } 2428 2429 res = scanned_icds->CreateInstance(&icd_create_info, 2430 &(icd->instance)); 2431 success = loader_icd_init_entrys( 2432 icd, 2433 icd->instance, 2434 scanned_icds->GetInstanceProcAddr); 2435 2436 if (res != VK_SUCCESS || !success) 2437 { 2438 ptr_instance->icds = ptr_instance->icds->next; 2439 loader_icd_destroy(ptr_instance, icd); 2440 icd->instance = VK_NULL_HANDLE; 2441 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, 2442 "ICD ignored: failed to CreateInstance and find entrypoints with ICD"); 2443 } 2444 } 2445 scanned_icds = scanned_icds->next; 2446 } 2447 2448 /* 2449 * If no ICDs were added to instance list and res is unchanged 2450 * from it's initial value, the loader was unable to find 2451 * a suitable ICD. 2452 */ 2453 if (ptr_instance->icds == NULL) { 2454 if (res == VK_SUCCESS) { 2455 return VK_ERROR_INCOMPATIBLE_DRIVER; 2456 } else { 2457 return res; 2458 } 2459 } 2460 2461 return VK_SUCCESS; 2462} 2463 2464VkResult VKAPI loader_DestroyInstance( 2465 VkInstance instance) 2466{ 2467 struct loader_instance *ptr_instance = loader_instance(instance); 2468 struct loader_icd *icds = ptr_instance->icds; 2469 struct loader_icd *next_icd; 2470 VkResult res; 2471 2472 // Remove this instance from the list of instances: 2473 struct loader_instance *prev = NULL; 2474 struct loader_instance *next = loader.instances; 2475 while (next != NULL) { 2476 if (next == ptr_instance) { 2477 // Remove this instance from the list: 2478 if (prev) 2479 prev->next = next->next; 2480 else 2481 loader.instances = next->next; 2482 break; 2483 } 2484 prev = next; 2485 next = next->next; 2486 } 2487 if (next == NULL) { 2488 // This must be an invalid instance handle or empty list 2489 return VK_ERROR_INVALID_HANDLE; 2490 } 2491 2492 while (icds) { 2493 if (icds->instance) { 2494 res = icds->DestroyInstance(icds->instance); 2495 if (res != VK_SUCCESS) 2496 loader_log(VK_DBG_REPORT_WARN_BIT, 0, 2497 "ICD ignored: failed to DestroyInstance on device"); 2498 } 2499 next_icd = icds->next; 2500 icds->instance = VK_NULL_HANDLE; 2501 loader_icd_destroy(ptr_instance, icds); 2502 2503 icds = next_icd; 2504 } 2505 2506 2507 return VK_SUCCESS; 2508} 2509 2510VkResult loader_init_physical_device_info( 2511 struct loader_instance *ptr_instance) 2512{ 2513 struct loader_icd *icd; 2514 uint32_t n, count = 0; 2515 VkResult res = VK_ERROR_UNKNOWN; 2516 2517 icd = ptr_instance->icds; 2518 while (icd) { 2519 res = icd->EnumeratePhysicalDevices(icd->instance, &n, NULL); 2520 if (res != VK_SUCCESS) 2521 return res; 2522 icd->gpu_count = n; 2523 count += n; 2524 icd = icd->next; 2525 } 2526 2527 ptr_instance->total_gpu_count = count; 2528 2529 icd = ptr_instance->icds; 2530 while (icd) { 2531 2532 n = icd->gpu_count; 2533 icd->gpus = (VkPhysicalDevice *) malloc(n * sizeof(VkPhysicalDevice)); 2534 if (!icd->gpus) { 2535 /* TODO: Add cleanup code here */ 2536 return VK_ERROR_OUT_OF_HOST_MEMORY; 2537 } 2538 res = icd->EnumeratePhysicalDevices( 2539 icd->instance, 2540 &n, 2541 icd->gpus); 2542 if ((res == VK_SUCCESS) && (n == icd->gpu_count)) { 2543 2544 for (unsigned int i = 0; i < n; i++) { 2545 2546 loader_init_dispatch(icd->gpus[i], ptr_instance->disp); 2547 2548 if (!loader_init_ext_list(&icd->device_extension_cache[i])) { 2549 /* TODO: Add cleanup code here */ 2550 res = VK_ERROR_OUT_OF_HOST_MEMORY; 2551 } 2552 if (res == VK_SUCCESS) { 2553 2554 loader_add_physical_device_extensions( 2555 icd->GetPhysicalDeviceExtensionProperties, 2556 icd->gpus[0], 2557 VK_EXTENSION_ORIGIN_ICD, 2558 icd->scanned_icds->lib_name, 2559 &icd->device_extension_cache[i]); 2560 2561 } 2562 2563 if (res != VK_SUCCESS) { 2564 /* clean up any extension lists previously created before this request failed */ 2565 for (uint32_t j = 0; j < i; j++) { 2566 loader_destroy_ext_list(&icd->device_extension_cache[i]); 2567 } 2568 2569 return res; 2570 } 2571 } 2572 2573 count += n; 2574 } 2575 2576 icd = icd->next; 2577 } 2578 2579 return VK_SUCCESS; 2580} 2581 2582VkResult VKAPI loader_EnumeratePhysicalDevices( 2583 VkInstance instance, 2584 uint32_t* pPhysicalDeviceCount, 2585 VkPhysicalDevice* pPhysicalDevices) 2586{ 2587 uint32_t index = 0; 2588 struct loader_instance *ptr_instance = (struct loader_instance *) instance; 2589 struct loader_icd *icd = ptr_instance->icds; 2590 2591 if (ptr_instance->total_gpu_count == 0) { 2592 loader_init_physical_device_info(ptr_instance); 2593 } 2594 2595 *pPhysicalDeviceCount = ptr_instance->total_gpu_count; 2596 if (!pPhysicalDevices) { 2597 return VK_SUCCESS; 2598 } 2599 2600 while (icd) { 2601 assert((index + icd->gpu_count) <= *pPhysicalDeviceCount); 2602 memcpy(&pPhysicalDevices[index], icd->gpus, icd->gpu_count * sizeof(VkPhysicalDevice)); 2603 index += icd->gpu_count; 2604 icd = icd->next; 2605 } 2606 2607 return VK_SUCCESS; 2608} 2609 2610VkResult VKAPI loader_GetPhysicalDeviceProperties( 2611 VkPhysicalDevice gpu, 2612 VkPhysicalDeviceProperties* pProperties) 2613{ 2614 uint32_t gpu_index; 2615 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index); 2616 VkResult res = VK_ERROR_INITIALIZATION_FAILED; 2617 2618 if (icd->GetPhysicalDeviceProperties) 2619 res = icd->GetPhysicalDeviceProperties(gpu, pProperties); 2620 2621 return res; 2622} 2623 2624VkResult VKAPI loader_GetPhysicalDeviceQueueCount( 2625 VkPhysicalDevice gpu, 2626 uint32_t* pCount) 2627{ 2628 uint32_t gpu_index; 2629 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index); 2630 VkResult res = VK_ERROR_INITIALIZATION_FAILED; 2631 2632 if (icd->GetPhysicalDeviceQueueCount) 2633 res = icd->GetPhysicalDeviceQueueCount(gpu, pCount); 2634 2635 return res; 2636} 2637 2638VkResult VKAPI loader_GetPhysicalDeviceQueueProperties ( 2639 VkPhysicalDevice gpu, 2640 uint32_t count, 2641 VkPhysicalDeviceQueueProperties * pProperties) 2642{ 2643 uint32_t gpu_index; 2644 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index); 2645 VkResult res = VK_ERROR_INITIALIZATION_FAILED; 2646 2647 if (icd->GetPhysicalDeviceQueueProperties) 2648 res = icd->GetPhysicalDeviceQueueProperties(gpu, count, pProperties); 2649 2650 return res; 2651} 2652 2653VkResult VKAPI loader_GetPhysicalDeviceMemoryProperties ( 2654 VkPhysicalDevice gpu, 2655 VkPhysicalDeviceMemoryProperties* pProperties) 2656{ 2657 uint32_t gpu_index; 2658 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index); 2659 VkResult res = VK_ERROR_INITIALIZATION_FAILED; 2660 2661 if (icd->GetPhysicalDeviceMemoryProperties) 2662 res = icd->GetPhysicalDeviceMemoryProperties(gpu, pProperties); 2663 2664 return res; 2665} 2666 2667VkResult VKAPI loader_GetPhysicalDeviceFeatures( 2668 VkPhysicalDevice physicalDevice, 2669 VkPhysicalDeviceFeatures* pFeatures) 2670{ 2671 uint32_t gpu_index; 2672 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index); 2673 VkResult res = VK_ERROR_INITIALIZATION_FAILED; 2674 2675 if (icd->GetPhysicalDeviceFeatures) 2676 res = icd->GetPhysicalDeviceFeatures(physicalDevice, pFeatures); 2677 2678 return res; 2679} 2680 2681VkResult VKAPI loader_GetPhysicalDeviceFormatProperties( 2682 VkPhysicalDevice physicalDevice, 2683 VkFormat format, 2684 VkFormatProperties* pFormatInfo) 2685{ 2686 uint32_t gpu_index; 2687 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index); 2688 VkResult res = VK_ERROR_INITIALIZATION_FAILED; 2689 2690 if (icd->GetPhysicalDeviceFormatProperties) 2691 res = icd->GetPhysicalDeviceFormatProperties(physicalDevice, format, pFormatInfo); 2692 2693 return res; 2694} 2695 2696VkResult VKAPI loader_GetPhysicalDeviceImageFormatProperties( 2697 VkPhysicalDevice physicalDevice, 2698 VkFormat format, 2699 VkImageType type, 2700 VkImageTiling tiling, 2701 VkImageUsageFlags usage, 2702 VkImageFormatProperties* pImageFormatProperties) 2703{ 2704 uint32_t gpu_index; 2705 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index); 2706 VkResult res = VK_ERROR_INITIALIZATION_FAILED; 2707 2708 if (icd->GetPhysicalDeviceImageFormatProperties) 2709 res = icd->GetPhysicalDeviceImageFormatProperties(physicalDevice, format, 2710 type, tiling, usage, pImageFormatProperties); 2711 2712 return res; 2713} 2714 2715VkResult VKAPI loader_GetPhysicalDeviceLimits( 2716 VkPhysicalDevice physicalDevice, 2717 VkPhysicalDeviceLimits* pLimits) 2718{ 2719 uint32_t gpu_index; 2720 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index); 2721 VkResult res = VK_ERROR_INITIALIZATION_FAILED; 2722 2723 if (icd->GetPhysicalDeviceLimits) 2724 res = icd->GetPhysicalDeviceLimits(physicalDevice, pLimits); 2725 2726 return res; 2727} 2728 2729VkResult VKAPI loader_GetPhysicalDeviceSparseImageFormatProperties( 2730 VkPhysicalDevice physicalDevice, 2731 VkFormat format, 2732 VkImageType type, 2733 uint32_t samples, 2734 VkImageUsageFlags usage, 2735 VkImageTiling tiling, 2736 uint32_t* pNumProperties, 2737 VkSparseImageFormatProperties* pProperties) 2738{ 2739 uint32_t gpu_index; 2740 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index); 2741 VkResult res = VK_ERROR_INITIALIZATION_FAILED; 2742 2743 if (icd->GetPhysicalDeviceSparseImageFormatProperties) 2744 res = icd->GetPhysicalDeviceSparseImageFormatProperties(physicalDevice, format, type, samples, usage, tiling, pNumProperties, pProperties); 2745 2746 return res; 2747} 2748 2749VkResult VKAPI loader_CreateDevice( 2750 VkPhysicalDevice gpu, 2751 const VkDeviceCreateInfo* pCreateInfo, 2752 VkDevice* pDevice) 2753{ 2754 uint32_t gpu_index; 2755 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index); 2756 struct loader_device *dev; 2757 VkDeviceCreateInfo device_create_info; 2758 char **filtered_extension_names = NULL; 2759 VkResult res; 2760 2761 if (!icd->CreateDevice) { 2762 return VK_ERROR_INITIALIZATION_FAILED; 2763 } 2764 2765 res = loader_validate_layers(pCreateInfo->layerCount, 2766 pCreateInfo->ppEnabledLayerNames, 2767 &loader.scanned_device_layers); 2768 if (res != VK_SUCCESS) { 2769 return res; 2770 } 2771 2772 res = loader_validate_device_extensions(icd, gpu_index, pCreateInfo); 2773 if (res != VK_SUCCESS) { 2774 return res; 2775 } 2776 2777 /* 2778 * NOTE: Need to filter the extensions to only those 2779 * supported by the ICD. 2780 * No ICD will advertise support for layers. An ICD 2781 * library could support a layer, but it would be 2782 * independent of the actual ICD, just in the same library. 2783 */ 2784 filtered_extension_names = loader_stack_alloc(pCreateInfo->extensionCount * sizeof(char *)); 2785 if (!filtered_extension_names) { 2786 return VK_ERROR_OUT_OF_HOST_MEMORY; 2787 } 2788 2789 /* Copy user's data */ 2790 memcpy(&device_create_info, pCreateInfo, sizeof(VkDeviceCreateInfo)); 2791 2792 /* ICD's do not use layers */ 2793 device_create_info.layerCount = 0; 2794 device_create_info.ppEnabledLayerNames = NULL; 2795 2796 device_create_info.extensionCount = 0; 2797 device_create_info.ppEnabledExtensionNames = (const char * const *) filtered_extension_names; 2798 2799 for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) { 2800 const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i]; 2801 struct loader_extension_property *prop = get_extension_property(extension_name, 2802 &icd->device_extension_cache[gpu_index]); 2803 if (prop) { 2804 filtered_extension_names[device_create_info.extensionCount] = (char *) extension_name; 2805 device_create_info.extensionCount++; 2806 } 2807 } 2808 2809 res = icd->CreateDevice(gpu, pCreateInfo, pDevice); 2810 if (res != VK_SUCCESS) { 2811 return res; 2812 } 2813 2814 dev = loader_add_logical_device(*pDevice, &icd->logical_device_list); 2815 if (dev == NULL) { 2816 return VK_ERROR_OUT_OF_HOST_MEMORY; 2817 } 2818 PFN_vkGetDeviceProcAddr get_proc_addr = icd->GetDeviceProcAddr; 2819 loader_init_device_dispatch_table(&dev->loader_dispatch, get_proc_addr, 2820 *pDevice, *pDevice); 2821 2822 dev->loader_dispatch.CreateDevice = scratch_vkCreateDevice; 2823 loader_init_dispatch(*pDevice, &dev->loader_dispatch); 2824 2825 /* 2826 * Put together the complete list of extensions to enable 2827 * This includes extensions requested via environment variables. 2828 */ 2829 loader_enable_device_layers(icd, dev, pCreateInfo); 2830 2831 /* 2832 * Load the libraries and build the device chain 2833 * terminating with the selected device. 2834 */ 2835 loader_activate_device_layers(icd, dev, *pDevice); 2836 2837 res = dev->loader_dispatch.CreateDevice(gpu, pCreateInfo, pDevice); 2838 2839 dev->loader_dispatch.CreateDevice = icd->CreateDevice; 2840 2841 return res; 2842} 2843 2844static PFN_vkVoidFunction VKAPI loader_GetInstanceProcAddr(VkInstance instance, const char * pName) 2845{ 2846 if (instance == VK_NULL_HANDLE) 2847 return NULL; 2848 2849 void *addr; 2850 /* get entrypoint addresses that are global (in the loader)*/ 2851 addr = globalGetProcAddr(pName); 2852 if (addr) 2853 return addr; 2854 2855 struct loader_instance *ptr_instance = (struct loader_instance *) instance; 2856 2857 /* return any extension global entrypoints */ 2858 addr = debug_report_instance_gpa(ptr_instance, pName); 2859 if (addr) { 2860 return addr; 2861 } 2862 2863 addr = wsi_swapchain_GetInstanceProcAddr(ptr_instance, pName); 2864 if (addr) { 2865 return addr; 2866 } 2867 2868 /* return the instance dispatch table entrypoint for extensions */ 2869 const VkLayerInstanceDispatchTable *disp_table = * (VkLayerInstanceDispatchTable **) instance; 2870 if (disp_table == NULL) 2871 return NULL; 2872 2873 addr = loader_lookup_instance_dispatch_table(disp_table, pName); 2874 if (addr) 2875 return addr; 2876 2877 return NULL; 2878} 2879 2880LOADER_EXPORT PFN_vkVoidFunction VKAPI vkGetInstanceProcAddr(VkInstance instance, const char * pName) 2881{ 2882 return loader_GetInstanceProcAddr(instance, pName); 2883} 2884 2885static PFN_vkVoidFunction VKAPI loader_GetDeviceProcAddr(VkDevice device, const char * pName) 2886{ 2887 if (device == VK_NULL_HANDLE) { 2888 return NULL; 2889 } 2890 2891 void *addr; 2892 2893 /* for entrypoints that loader must handle (ie non-dispatchable or create object) 2894 make sure the loader entrypoint is returned */ 2895 addr = loader_non_passthrough_gpa(pName); 2896 if (addr) { 2897 return addr; 2898 } 2899 2900 /* return the dispatch table entrypoint for the fastest case */ 2901 const VkLayerDispatchTable *disp_table = * (VkLayerDispatchTable **) device; 2902 if (disp_table == NULL) 2903 return NULL; 2904 2905 addr = loader_lookup_device_dispatch_table(disp_table, pName); 2906 if (addr) 2907 return addr; 2908 else { 2909 if (disp_table->GetDeviceProcAddr == NULL) 2910 return NULL; 2911 return disp_table->GetDeviceProcAddr(device, pName); 2912 } 2913} 2914 2915LOADER_EXPORT PFN_vkVoidFunction VKAPI vkGetDeviceProcAddr(VkDevice device, const char * pName) 2916{ 2917 return loader_GetDeviceProcAddr(device, pName); 2918} 2919 2920LOADER_EXPORT VkResult VKAPI vkGetGlobalExtensionProperties( 2921 const char* pLayerName, 2922 uint32_t* pCount, 2923 VkExtensionProperties* pProperties) 2924{ 2925 struct loader_extension_list *global_extension_list; 2926 2927 /* Scan/discover all ICD libraries in a single-threaded manner */ 2928 loader_platform_thread_once(&once_icd, loader_icd_scan); 2929 2930 /* get layer libraries in a single-threaded manner */ 2931 loader_platform_thread_once(&once_layer, loader_layer_scan); 2932 2933 /* merge any duplicate extensions */ 2934 loader_platform_thread_once(&once_exts, loader_coalesce_extensions); 2935 2936 uint32_t copy_size; 2937 2938 if (pCount == NULL) { 2939 return VK_ERROR_INVALID_POINTER; 2940 } 2941 2942 loader_platform_thread_lock_mutex(&loader_lock); 2943 2944 global_extension_list = loader_global_extensions(pLayerName); 2945 if (global_extension_list == NULL) { 2946 loader_platform_thread_unlock_mutex(&loader_lock); 2947 return VK_ERROR_INVALID_LAYER; 2948 } 2949 2950 if (pProperties == NULL) { 2951 *pCount = global_extension_list->count; 2952 loader_platform_thread_unlock_mutex(&loader_lock); 2953 return VK_SUCCESS; 2954 } 2955 2956 copy_size = *pCount < global_extension_list->count ? *pCount : global_extension_list->count; 2957 for (uint32_t i = 0; i < copy_size; i++) { 2958 memcpy(&pProperties[i], 2959 &global_extension_list->list[i].info, 2960 sizeof(VkExtensionProperties)); 2961 } 2962 *pCount = copy_size; 2963 2964 loader_platform_thread_unlock_mutex(&loader_lock); 2965 2966 if (copy_size < global_extension_list->count) { 2967 return VK_INCOMPLETE; 2968 } 2969 2970 return VK_SUCCESS; 2971} 2972 2973LOADER_EXPORT VkResult VKAPI vkGetGlobalLayerProperties( 2974 uint32_t* pCount, 2975 VkLayerProperties* pProperties) 2976{ 2977 2978 /* Scan/discover all ICD libraries in a single-threaded manner */ 2979 loader_platform_thread_once(&once_icd, loader_icd_scan); 2980 2981 /* get layer libraries in a single-threaded manner */ 2982 loader_platform_thread_once(&once_layer, loader_layer_scan); 2983 2984 /* merge any duplicate extensions */ 2985 loader_platform_thread_once(&once_exts, loader_coalesce_extensions); 2986 2987 uint32_t copy_size; 2988 2989 if (pCount == NULL) { 2990 return VK_ERROR_INVALID_POINTER; 2991 } 2992 2993 /* TODO: do we still need to lock */ 2994 loader_platform_thread_lock_mutex(&loader_lock); 2995 2996 struct loader_layer_list *layer_list; 2997 layer_list = &loader.scanned_instance_layers; 2998 2999 if (pProperties == NULL) { 3000 *pCount = layer_list->count; 3001 loader_platform_thread_unlock_mutex(&loader_lock); 3002 return VK_SUCCESS; 3003 } 3004 3005 copy_size = *pCount < layer_list->count ? *pCount : layer_list->count; 3006 for (uint32_t i = 0; i < copy_size; i++) { 3007 memcpy(&pProperties[i], &layer_list->list[i].info, sizeof(VkLayerProperties)); 3008 } 3009 *pCount = copy_size; 3010 3011 loader_platform_thread_unlock_mutex(&loader_lock); 3012 3013 if (copy_size < layer_list->count) { 3014 return VK_INCOMPLETE; 3015 } 3016 3017 return VK_SUCCESS; 3018} 3019 3020VkResult VKAPI loader_GetPhysicalDeviceExtensionProperties( 3021 VkPhysicalDevice gpu, 3022 const char* pLayerName, 3023 uint32_t* pCount, 3024 VkExtensionProperties* pProperties) 3025{ 3026 uint32_t gpu_index; 3027 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index); 3028 uint32_t copy_size; 3029 3030 if (pCount == NULL) { 3031 return VK_ERROR_INVALID_POINTER; 3032 } 3033 3034 uint32_t count; 3035 struct loader_extension_list *list; 3036 loader_physical_device_extensions(icd, gpu_index, pLayerName, &count, &list); 3037 3038 if (pProperties == NULL) { 3039 *pCount = count; 3040 return VK_SUCCESS; 3041 } 3042 3043 copy_size = *pCount < count ? *pCount : count; 3044 for (uint32_t i = 0; i < copy_size; i++) { 3045 memcpy(&pProperties[i], 3046 &list->list[i].info, 3047 sizeof(VkExtensionProperties)); 3048 } 3049 *pCount = copy_size; 3050 3051 if (copy_size < count) { 3052 return VK_INCOMPLETE; 3053 } 3054 3055 return VK_SUCCESS; 3056} 3057 3058VkResult VKAPI loader_GetPhysicalDeviceLayerProperties( 3059 VkPhysicalDevice gpu, 3060 uint32_t* pCount, 3061 VkLayerProperties* pProperties) 3062{ 3063 uint32_t copy_size; 3064 3065 if (pCount == NULL) { 3066 return VK_ERROR_INVALID_POINTER; 3067 } 3068 3069 uint32_t count = loader.scanned_device_layers.count; 3070 struct loader_layer_list *layer_list = &loader.scanned_device_layers; 3071 3072 if (pProperties == NULL) { 3073 *pCount = count; 3074 return VK_SUCCESS; 3075 } 3076 3077 copy_size = *pCount < count ? *pCount : count; 3078 for (uint32_t i = 0; i < copy_size; i++) { 3079 memcpy(&pProperties[i], 3080 &layer_list->list[i].info, 3081 sizeof(VkLayerProperties)); 3082 } 3083 *pCount = copy_size; 3084 3085 if (copy_size < count) { 3086 return VK_INCOMPLETE; 3087 } 3088 3089 return VK_SUCCESS; 3090} 3091