3 * Copyright (c) 2014-2018 The Khronos Group Inc.
4 * Copyright (c) 2014-2018 Valve Corporation
5 * Copyright (c) 2014-2018 LunarG, Inc.
6 * Copyright (C) 2015 Google Inc.
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
21 * Author: Jon Ashburn <jon@lunarg.com>
22 * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
23 * Author: Mark Young <marky@lunarg.com>
24 * Author: Lenny Komow <lenny@lunarg.com>
36 #include <sys/types.h>
38 #include "dirent_on_windows.h"
42 #include "vk_loader_platform.h"
44 #include "gpa_helper.h"
45 #include "debug_report.h"
47 #include "vulkan/vk_icd.h"
49 #include "murmurhash.h"
57 // This is a CMake generated file with #defines for any functions/includes
58 // that it found present. This is currently necessary to properly determine
59 // if secure_getenv or __secure_getenv are present
60 #if !defined(VULKAN_NON_CMAKE_BUILD)
61 #include "loader_cmake_config.h"
62 #endif // !defined(VULKAN_NON_CMAKE_BUILD)
64 // Generated file containing all the extension data
65 #include "vk_loader_extensions.c"
67 struct loader_struct loader = {0};
68 // TLS for instance for alloc/free callbacks
69 THREAD_LOCAL_DECL struct loader_instance *tls_instance;
71 static size_t loader_platform_combine_path(char *dest, size_t len, ...);
73 struct loader_phys_dev_per_icd {
75 VkPhysicalDevice *phys_devs;
76 struct loader_icd_term *this_icd_term;
80 LOADER_INFO_BIT = 0x01,
81 LOADER_WARN_BIT = 0x02,
82 LOADER_PERF_BIT = 0x04,
83 LOADER_ERROR_BIT = 0x08,
84 LOADER_DEBUG_BIT = 0x10,
87 uint32_t g_loader_debug = 0;
88 uint32_t g_loader_log_msgs = 0;
90 // thread safety lock for accessing global data structures such as "loader"
91 // all entrypoints on the instance chain need to be locked except GPA
92 // additionally CreateDevice and DestroyDevice needs to be locked
93 loader_platform_thread_mutex loader_lock;
94 loader_platform_thread_mutex loader_json_lock;
96 LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_init);
98 void *loader_instance_heap_alloc(const struct loader_instance *instance, size_t size, VkSystemAllocationScope alloc_scope) {
100 #if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
103 if (instance && instance->alloc_callbacks.pfnAllocation) {
104 // These are internal structures, so it's best to align everything to
105 // the largest unit size which is the size of a uint64_t.
106 pMemory = instance->alloc_callbacks.pfnAllocation(instance->alloc_callbacks.pUserData, size, sizeof(uint64_t), alloc_scope);
109 pMemory = malloc(size);
115 void loader_instance_heap_free(const struct loader_instance *instance, void *pMemory) {
116 if (pMemory != NULL) {
117 #if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
120 if (instance && instance->alloc_callbacks.pfnFree) {
121 instance->alloc_callbacks.pfnFree(instance->alloc_callbacks.pUserData, pMemory);
129 void *loader_instance_heap_realloc(const struct loader_instance *instance, void *pMemory, size_t orig_size, size_t size,
130 VkSystemAllocationScope alloc_scope) {
131 void *pNewMem = NULL;
132 if (pMemory == NULL || orig_size == 0) {
133 pNewMem = loader_instance_heap_alloc(instance, size, alloc_scope);
134 } else if (size == 0) {
135 loader_instance_heap_free(instance, pMemory);
136 #if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
138 } else if (instance && instance->alloc_callbacks.pfnReallocation) {
139 // These are internal structures, so it's best to align everything to
140 // the largest unit size which is the size of a uint64_t.
141 pNewMem = instance->alloc_callbacks.pfnReallocation(instance->alloc_callbacks.pUserData, pMemory, size, sizeof(uint64_t),
145 pNewMem = realloc(pMemory, size);
150 void *loader_instance_tls_heap_alloc(size_t size) {
151 return loader_instance_heap_alloc(tls_instance, size, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
154 void loader_instance_tls_heap_free(void *pMemory) { loader_instance_heap_free(tls_instance, pMemory); }
156 void *loader_device_heap_alloc(const struct loader_device *device, size_t size, VkSystemAllocationScope alloc_scope) {
157 void *pMemory = NULL;
158 #if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
161 if (device && device->alloc_callbacks.pfnAllocation) {
162 // These are internal structures, so it's best to align everything to
163 // the largest unit size which is the size of a uint64_t.
164 pMemory = device->alloc_callbacks.pfnAllocation(device->alloc_callbacks.pUserData, size, sizeof(uint64_t), alloc_scope);
167 pMemory = malloc(size);
172 void loader_device_heap_free(const struct loader_device *device, void *pMemory) {
173 if (pMemory != NULL) {
174 #if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
177 if (device && device->alloc_callbacks.pfnFree) {
178 device->alloc_callbacks.pfnFree(device->alloc_callbacks.pUserData, pMemory);
186 void *loader_device_heap_realloc(const struct loader_device *device, void *pMemory, size_t orig_size, size_t size,
187 VkSystemAllocationScope alloc_scope) {
188 void *pNewMem = NULL;
189 if (pMemory == NULL || orig_size == 0) {
190 pNewMem = loader_device_heap_alloc(device, size, alloc_scope);
191 } else if (size == 0) {
192 loader_device_heap_free(device, pMemory);
193 #if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
195 } else if (device && device->alloc_callbacks.pfnReallocation) {
196 // These are internal structures, so it's best to align everything to
197 // the largest unit size which is the size of a uint64_t.
198 pNewMem = device->alloc_callbacks.pfnReallocation(device->alloc_callbacks.pUserData, pMemory, size, sizeof(uint64_t),
202 pNewMem = realloc(pMemory, size);
207 // Environment variables
208 #if defined(__linux__)
210 static inline char *loader_getenv(const char *name, const struct loader_instance *inst) {
211 // No allocation of memory necessary for Linux, but we should at least touch
212 // the inst pointer to get rid of compiler warnings.
217 static inline char *loader_secure_getenv(const char *name, const struct loader_instance *inst) {
218 // No allocation of memory necessary for Linux, but we should at least touch
219 // the inst pointer to get rid of compiler warnings.
222 #ifdef HAVE_SECURE_GETENV
223 return secure_getenv(name);
224 #elif defined(HAVE___SECURE_GETENV)
225 return __secure_getenv(name);
228 "Warning: Falling back to non-secure getenv for environmental lookups! Consider" \
229 " updating to a different libc.")
230 return loader_getenv(name, inst);
234 static inline void loader_free_getenv(char *val, const struct loader_instance *inst) {
235 // No freeing of memory necessary for Linux, but we should at least touch
236 // the val and inst pointers to get rid of compiler warnings.
243 static inline char *loader_getenv(const char *name, const struct loader_instance *inst) {
247 valSize = GetEnvironmentVariableA(name, NULL, 0);
249 // valSize DOES include the null terminator, so for any set variable
250 // will always be at least 1. If it's 0, the variable wasn't set.
251 if (valSize == 0) return NULL;
253 // Allocate the space necessary for the registry entry
254 if (NULL != inst && NULL != inst->alloc_callbacks.pfnAllocation) {
255 retVal = (char *)inst->alloc_callbacks.pfnAllocation(inst->alloc_callbacks.pUserData, valSize, sizeof(char *),
256 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
258 retVal = (char *)malloc(valSize);
261 if (NULL != retVal) {
262 GetEnvironmentVariableA(name, retVal, valSize);
268 static inline char *loader_secure_getenv(const char *name, const struct loader_instance *inst) {
269 // No secure version for Windows as far as I know
270 return loader_getenv(name, inst);
273 static inline void loader_free_getenv(char *val, const struct loader_instance *inst) {
274 if (NULL != inst && NULL != inst->alloc_callbacks.pfnFree) {
275 inst->alloc_callbacks.pfnFree(inst->alloc_callbacks.pUserData, val);
283 static inline char *loader_getenv(const char *name, const struct loader_instance *inst) {
289 static inline void loader_free_getenv(char *val, const struct loader_instance *inst) {
297 void loader_log(const struct loader_instance *inst, VkFlags msg_type, int32_t msg_code, const char *format, ...) {
299 char cmd_line_msg[512];
300 size_t cmd_line_size = sizeof(cmd_line_msg);
304 va_start(ap, format);
305 ret = vsnprintf(msg, sizeof(msg), format, ap);
306 if ((ret >= (int)sizeof(msg)) || ret < 0) {
307 msg[sizeof(msg) - 1] = '\0';
312 util_DebugReportMessage(inst, msg_type, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, (uint64_t)(uintptr_t)inst, 0, msg_code,
316 if (!(msg_type & g_loader_log_msgs)) {
320 cmd_line_msg[0] = '\0';
322 size_t original_size = cmd_line_size;
324 va_start(ap, format);
325 if ((msg_type & LOADER_INFO_BIT) != 0) {
326 strncat(cmd_line_msg, "INFO", cmd_line_size);
329 if ((msg_type & LOADER_WARN_BIT) != 0) {
330 if (cmd_line_size != original_size) {
331 strncat(cmd_line_msg, " | ", cmd_line_size);
334 strncat(cmd_line_msg, "WARNING", cmd_line_size);
337 if ((msg_type & LOADER_PERF_BIT) != 0) {
338 if (cmd_line_size != original_size) {
339 strncat(cmd_line_msg, " | ", cmd_line_size);
342 strncat(cmd_line_msg, "PERF", cmd_line_size);
345 if ((msg_type & LOADER_ERROR_BIT) != 0) {
346 if (cmd_line_size != original_size) {
347 strncat(cmd_line_msg, " | ", cmd_line_size);
350 strncat(cmd_line_msg, "ERROR", cmd_line_size);
353 if ((msg_type & LOADER_DEBUG_BIT) != 0) {
354 if (cmd_line_size != original_size) {
355 strncat(cmd_line_msg, " | ", cmd_line_size);
358 strncat(cmd_line_msg, "DEBUG", cmd_line_size);
361 if (cmd_line_size != original_size) {
362 strncat(cmd_line_msg, ": ", cmd_line_size);
366 if (0 < cmd_line_size) {
367 // If the message is too long, trim it down
368 if (strlen(msg) > cmd_line_size) {
369 msg[cmd_line_size - 1] = '\0';
371 strncat(cmd_line_msg, msg, cmd_line_size);
373 // Shouldn't get here, but check to make sure if we've already overrun
374 // the string boundary
379 OutputDebugString(cmd_line_msg);
380 OutputDebugString("\n");
383 fputs(cmd_line_msg, stderr);
387 VKAPI_ATTR VkResult VKAPI_CALL vkSetInstanceDispatch(VkInstance instance, void *object) {
388 struct loader_instance *inst = loader_get_instance(instance);
390 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
391 "vkSetInstanceDispatch: Can not retrieve Instance "
393 return VK_ERROR_INITIALIZATION_FAILED;
395 loader_set_dispatch(object, inst->disp);
399 VKAPI_ATTR VkResult VKAPI_CALL vkSetDeviceDispatch(VkDevice device, void *object) {
400 struct loader_device *dev;
401 struct loader_icd_term *icd_term = loader_get_icd_and_device(device, &dev, NULL);
403 if (NULL == icd_term) {
404 return VK_ERROR_INITIALIZATION_FAILED;
406 loader_set_dispatch(object, &dev->loader_dispatch);
412 // Append the JSON path data to the list and allocate/grow the list if it's not large enough.
413 // Function returns true if filename was appended to reg_data list.
414 // Caller should free reg_data.
415 static bool loaderAddJsonEntry(const struct loader_instance *inst,
416 char **reg_data, // list of JSON files
417 PDWORD total_size, // size of reg_data
418 LPCTSTR key_name, // key name - used for debug prints - i.e. VulkanDriverName
419 DWORD key_type, // key data type
420 LPSTR json_path, // JSON string to add to the list reg_data
421 DWORD json_size, // size in bytes of json_path
423 if (NULL == *reg_data) {
424 *reg_data = loader_instance_heap_alloc(inst, *total_size, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
425 if (NULL == *reg_data) {
426 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
427 "loaderAddJsonEntry: Failed to allocate space for registry data for key %s", json_path);
428 *result = VK_ERROR_OUT_OF_HOST_MEMORY;
432 } else if (strlen(*reg_data) + json_size + 1 > *total_size) {
434 loader_instance_heap_realloc(inst, *reg_data, *total_size, *total_size * 2, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
435 if (NULL == new_ptr) {
436 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
437 "loaderAddJsonEntry: Failed to reallocate space for registry value of size %d for key %s", *total_size * 2,
439 *result = VK_ERROR_OUT_OF_HOST_MEMORY;
446 for (char *curr_filename = json_path; curr_filename[0] != '\0'; curr_filename += strlen(curr_filename) + 1) {
447 if (strlen(*reg_data) == 0) {
448 (void)snprintf(*reg_data, json_size + 1, "%s", curr_filename);
450 (void)snprintf(*reg_data + strlen(*reg_data), json_size + 2, "%c%s", PATH_SEPARATOR, curr_filename);
452 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "%s: Located json file \"%s\" from PnP registry: %s", __FUNCTION__,
453 curr_filename, key_name);
455 if (key_type == REG_SZ) {
462 // Find the list of registry files (names VulkanDriverName/VulkanDriverNameWow) in hkr.
464 // This function looks for filename in given device handle, filename is then added to return list
465 // function return true if filename was appended to reg_data list
466 // If error occures result is updated with failure reason
467 bool loaderGetDeviceRegistryEntry(const struct loader_instance *inst, char **reg_data, PDWORD total_size, DEVINST dev_id, LPCTSTR value_name, VkResult *result)
469 HKEY hkrKey = INVALID_HANDLE_VALUE;
470 DWORD requiredSize, data_type;
471 char *manifest_path = NULL;
474 if (NULL == total_size || NULL == reg_data) {
475 *result = VK_ERROR_INITIALIZATION_FAILED;
479 CONFIGRET status = CM_Open_DevNode_Key(dev_id, KEY_QUERY_VALUE, 0, RegDisposition_OpenExisting, &hkrKey, CM_REGISTRY_SOFTWARE);
480 if (status != CR_SUCCESS) {
481 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
482 "loaderGetDeviceRegistryEntry: Failed to open registry key for DeviceID(%d)", dev_id);
483 *result = VK_ERROR_INITIALIZATION_FAILED;
488 LSTATUS ret = RegQueryValueEx(
496 if (ret != ERROR_SUCCESS) {
497 if (ret == ERROR_FILE_NOT_FOUND) {
498 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
499 "loaderGetDeviceRegistryEntry: Device ID(%d) Does not contain a value for \"%s\"", dev_id, value_name);
501 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
502 "loaderGetDeviceRegistryEntry: DeviceID(%d) Failed to obtain %s size", dev_id, value_name);
507 manifest_path = loader_instance_heap_alloc(inst, requiredSize, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
508 if (manifest_path == NULL) {
509 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
510 "loaderGetDeviceRegistryEntry: Failed to allocate space for DriverName.");
511 *result = VK_ERROR_OUT_OF_HOST_MEMORY;
515 ret = RegQueryValueEx(
520 (BYTE *)manifest_path,
524 if (ret != ERROR_SUCCESS) {
525 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
526 "loaderGetDeviceRegistryEntry: DeviceID(%d) Failed to obtain %s", value_name);
528 *result = VK_ERROR_INITIALIZATION_FAILED;
532 if (data_type != REG_SZ && data_type != REG_MULTI_SZ) {
533 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
534 "loaderGetDeviceRegistryEntry: Invalid %s data type. Expected REG_SZ or REG_MULTI_SZ.", value_name);
535 *result = VK_ERROR_INITIALIZATION_FAILED;
539 found = loaderAddJsonEntry(inst, reg_data, total_size, value_name, data_type, manifest_path, requiredSize, result);
542 if (manifest_path != NULL) {
543 loader_instance_heap_free(inst, manifest_path);
549 // Find the list of registry files (names VulkanDriverName/VulkanDriverNameWow) in hkr .
551 // This function looks for display devices and childish software components
552 // for a list of files which are added to a returned list (function return
554 // Function return is a string with a ';' separated list of filenames.
555 // Function return is NULL if no valid name/value pairs are found in the key,
556 // or the key is not found.
558 // *reg_data contains a string list of filenames as pointer.
559 // When done using the returned string list, the caller should free the pointer.
560 VkResult loaderGetDeviceRegistryFiles(const struct loader_instance *inst, char **reg_data, PDWORD reg_data_size, LPCTSTR value_name) {
561 static const wchar_t *softwareComponentGUID = L"{5c4c3332-344d-483c-8739-259e934c9cc8}";
562 static const wchar_t *displayGUID = L"{4d36e968-e325-11ce-bfc1-08002be10318}";
563 const ULONG flags = CM_GETIDLIST_FILTER_CLASS | CM_GETIDLIST_FILTER_PRESENT;
565 wchar_t childGuid[MAX_GUID_STRING_LEN + 2]; // +2 for brackets {}
566 ULONG childGuidSize = sizeof(childGuid);
568 DEVINST devID = 0, childID = 0;
569 wchar_t *pDeviceNames = NULL;
570 ULONG deviceNamesSize = 0;
571 VkResult result = VK_SUCCESS;
574 if (NULL == reg_data) {
575 result = VK_ERROR_INITIALIZATION_FAILED;
579 // if after obtaining the DeviceNameSize, new device is added start over
581 CM_Get_Device_ID_List_SizeW(&deviceNamesSize, displayGUID, flags);
583 if (pDeviceNames != NULL) {
584 loader_instance_heap_free(inst, pDeviceNames);
587 pDeviceNames = loader_instance_heap_alloc(inst, deviceNamesSize * sizeof(wchar_t), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
588 if (pDeviceNames == NULL) {
589 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
590 "loaderGetDeviceRegistryFiles: Failed to allocate space for display device names.");
591 result = VK_ERROR_OUT_OF_HOST_MEMORY;
594 } while (CM_Get_Device_ID_ListW(displayGUID, pDeviceNames, deviceNamesSize, flags) == CR_BUFFER_SMALL);
597 for (wchar_t *deviceName = pDeviceNames; *deviceName; deviceName += wcslen(deviceName) + 1) {
598 CONFIGRET status = CM_Locate_DevNodeW(&devID, deviceName, CM_LOCATE_DEVNODE_NORMAL);
599 if (CR_SUCCESS != status) {
600 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, "loaderGetDeviceRegistryFiles: failed to open DevNode %s",
604 ULONG ulStatus, ulProblem;
605 status = CM_Get_DevNode_Status(&ulStatus, &ulProblem, devID, 0);
607 if (CR_SUCCESS != status)
609 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, "loaderGetDeviceRegistryFiles: failed to probe device status %s",
613 if ((ulStatus & DN_HAS_PROBLEM) && (ulProblem == CM_PROB_NEED_RESTART || ulProblem == DN_NEED_RESTART))
615 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
616 "loaderGetDeviceRegistryFiles: device %s is pending reboot, skipping ...", deviceName);
620 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "loaderGetDeviceRegistryFiles: opening device %s", deviceName);
622 if (loaderGetDeviceRegistryEntry(inst, reg_data, reg_data_size, devID, value_name, &result)) {
626 else if (result == VK_ERROR_OUT_OF_HOST_MEMORY) {
630 status = CM_Get_Child(&childID, devID, 0);
631 if (status != CR_SUCCESS) {
632 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
633 "loaderGetDeviceRegistryFiles: unable to open child-device error:%d", status);
638 wchar_t buffer[MAX_DEVICE_ID_LEN];
639 CM_Get_Device_IDW(childID, buffer, MAX_DEVICE_ID_LEN, 0);
641 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
642 "loaderGetDeviceRegistryFiles: Opening child device %d - %s", childID, buffer);
644 status = CM_Get_DevNode_Registry_PropertyW(childID, CM_DRP_CLASSGUID, NULL, &childGuid, &childGuidSize, 0);
645 if (status != CR_SUCCESS) {
646 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
647 "loaderGetDeviceRegistryFiles: unable to obtain GUID for:%d error:%d", childID, status);
649 result = VK_ERROR_INITIALIZATION_FAILED;
653 if (wcscmp(childGuid, softwareComponentGUID) != 0) {
654 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
655 "loaderGetDeviceRegistryFiles: GUID for %d is not SoftwareComponent skipping", childID);
659 if (loaderGetDeviceRegistryEntry(inst, reg_data, reg_data_size, childID, value_name, &result)) {
661 break; // check next-display-device
664 } while (CM_Get_Sibling(&childID, childID, 0) == CR_SUCCESS);
667 loader_instance_heap_free(inst, pDeviceNames);
670 if (!found && result != VK_ERROR_OUT_OF_HOST_MEMORY) {
671 result = VK_ERROR_INITIALIZATION_FAILED;
677 static char *loader_get_next_path(char *path);
679 // Find the list of registry files (names within a key) in key "location".
681 // This function looks in the registry (hive = DEFAULT_VK_REGISTRY_HIVE) key as
682 // given in "location"
683 // for a list or name/values which are added to a returned list (function return
685 // The DWORD values within the key must be 0 or they are skipped.
686 // Function return is a string with a ';' separated list of filenames.
687 // Function return is NULL if no valid name/value pairs are found in the key,
688 // or the key is not found.
690 // *reg_data contains a string list of filenames as pointer.
691 // When done using the returned string list, the caller should free the pointer.
692 VkResult loaderGetRegistryFiles(const struct loader_instance *inst, char *location, bool use_secondary_hive, char **reg_data, PDWORD reg_data_size) {
694 HKEY hive = DEFAULT_VK_REGISTRY_HIVE, key;
697 char *loc = location;
700 DWORD name_size = sizeof(name);
702 DWORD value_size = sizeof(value);
703 VkResult result = VK_SUCCESS;
706 if (NULL == reg_data) {
707 result = VK_ERROR_INITIALIZATION_FAILED;
712 next = loader_get_next_path(loc);
713 access_flags = KEY_QUERY_VALUE;
714 rtn_value = RegOpenKeyEx(hive, loc, 0, access_flags, &key);
715 if (ERROR_SUCCESS == rtn_value) {
717 while ((rtn_value = RegEnumValue(key, idx++, name, &name_size, NULL, NULL, (LPBYTE)&value, &value_size)) ==
719 if (value_size == sizeof(value) && value == 0) {
720 if (NULL == *reg_data) {
721 *reg_data = loader_instance_heap_alloc(inst, *reg_data_size, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
722 if (NULL == *reg_data) {
723 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
724 "loaderGetRegistryFiles: Failed to allocate space for registry data for key %s", name);
726 result = VK_ERROR_OUT_OF_HOST_MEMORY;
730 } else if (strlen(*reg_data) + name_size + 1 > *reg_data_size) {
731 void *new_ptr = loader_instance_heap_realloc(inst, *reg_data, *reg_data_size, *reg_data_size * 2,
732 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
733 if (NULL == new_ptr) {
735 inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
736 "loaderGetRegistryFiles: Failed to reallocate space for registry value of size %d for key %s",
737 *reg_data_size * 2, name);
739 result = VK_ERROR_OUT_OF_HOST_MEMORY;
746 inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "Located json file \"%s\" from registry \"%s\\%s\"", name,
747 hive == DEFAULT_VK_REGISTRY_HIVE ? DEFAULT_VK_REGISTRY_HIVE_STR : SECONDARY_VK_REGISTRY_HIVE_STR, location);
748 if (strlen(*reg_data) == 0) {
749 // The list is emtpy. Add the first entry.
750 (void)snprintf(*reg_data, name_size + 1, "%s", name);
753 // At this point the reg_data variable contains other JSON paths, likely from the PNP/device section
754 // of the registry that we want to have precendence over this non-device specific section of the registry.
755 // To make sure we avoid enumerating old JSON files/drivers that might be present in the non-device specific
756 // area of the registry when a newer device specific JSON file is present, do a check before adding.
757 // Find the file name, without path, of the JSON file found in the non-device specific registry location.
758 // If the same JSON file name is already found in the list, don't add it again.
759 bool foundDuplicate = false;
760 char *pLastSlashName = strrchr(name, '\\');
761 if (pLastSlashName != NULL) {
762 char *foundMatch = strstr(*reg_data, pLastSlashName + 1);
763 if (foundMatch != NULL) {
764 foundDuplicate = true;
768 if (foundDuplicate == false) {
769 // Add the new entry to the list.
770 (void)snprintf(*reg_data + strlen(*reg_data), name_size + 2, "%c%s", PATH_SEPARATOR, name);
774 inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
775 "Skipping adding of json file \"%s\" from registry \"%s\\%s\" to the list due to duplication", name,
776 hive == DEFAULT_VK_REGISTRY_HIVE ? DEFAULT_VK_REGISTRY_HIVE_STR : SECONDARY_VK_REGISTRY_HIVE_STR,
786 // Advance the location - if the next location is in the secondary hive, then reset the locations and advance the hive
787 if (use_secondary_hive && (hive == DEFAULT_VK_REGISTRY_HIVE) && (*next == '\0')) {
789 hive = SECONDARY_VK_REGISTRY_HIVE;
795 if (!found && result != VK_ERROR_OUT_OF_HOST_MEMORY) {
796 result = VK_ERROR_INITIALIZATION_FAILED;
806 // Combine path elements, separating each element with the platform-specific
807 // directory separator, and save the combined string to a destination buffer,
808 // not exceeding the given length. Path elements are given as variable args,
809 // with a NULL element terminating the list.
811 // \returns the total length of the combined string, not including an ASCII
812 // NUL termination character. This length may exceed the available storage:
813 // in this case, the written string will be truncated to avoid a buffer
814 // overrun, and the return value will greater than or equal to the storage
815 // size. A NULL argument may be provided as the destination buffer in order
816 // to determine the required string length without actually writing a string.
817 static size_t loader_platform_combine_path(char *dest, size_t len, ...) {
818 size_t required_len = 0;
820 const char *component;
824 while ((component = va_arg(ap, const char *))) {
825 if (required_len > 0) {
826 // This path element is not the first non-empty element; prepend
827 // a directory separator if space allows
828 if (dest && required_len + 1 < len) {
829 (void)snprintf(dest + required_len, len - required_len, "%c", DIRECTORY_SYMBOL);
834 if (dest && required_len < len) {
835 strncpy(dest + required_len, component, len - required_len);
837 required_len += strlen(component);
842 // strncpy(3) won't add a NUL terminating byte in the event of truncation.
843 if (dest && required_len >= len) {
844 dest[len - 1] = '\0';
850 // Given string of three part form "maj.min.pat" convert to a vulkan version number.
851 static uint32_t loader_make_version(char *vers_str) {
852 uint32_t vers = 0, major = 0, minor = 0, patch = 0;
859 vers_tok = strtok(vers_str, ".\"\n\r");
860 if (NULL != vers_tok) {
861 major = (uint16_t)atoi(vers_tok);
862 vers_tok = strtok(NULL, ".\"\n\r");
863 if (NULL != vers_tok) {
864 minor = (uint16_t)atoi(vers_tok);
865 vers_tok = strtok(NULL, ".\"\n\r");
866 if (NULL != vers_tok) {
867 patch = (uint16_t)atoi(vers_tok);
872 return VK_MAKE_VERSION(major, minor, patch);
875 bool compare_vk_extension_properties(const VkExtensionProperties *op1, const VkExtensionProperties *op2) {
876 return strcmp(op1->extensionName, op2->extensionName) == 0 ? true : false;
879 // Search the given ext_array for an extension matching the given vk_ext_prop
880 bool has_vk_extension_property_array(const VkExtensionProperties *vk_ext_prop, const uint32_t count,
881 const VkExtensionProperties *ext_array) {
882 for (uint32_t i = 0; i < count; i++) {
883 if (compare_vk_extension_properties(vk_ext_prop, &ext_array[i])) return true;
888 // Search the given ext_list for an extension matching the given vk_ext_prop
889 bool has_vk_extension_property(const VkExtensionProperties *vk_ext_prop, const struct loader_extension_list *ext_list) {
890 for (uint32_t i = 0; i < ext_list->count; i++) {
891 if (compare_vk_extension_properties(&ext_list->list[i], vk_ext_prop)) return true;
896 // Search the given ext_list for a device extension matching the given ext_prop
897 bool has_vk_dev_ext_property(const VkExtensionProperties *ext_prop, const struct loader_device_extension_list *ext_list) {
898 for (uint32_t i = 0; i < ext_list->count; i++) {
899 if (compare_vk_extension_properties(&ext_list->list[i].props, ext_prop)) return true;
904 // Search the given layer list for a layer matching the given layer name
905 static struct loader_layer_properties *loader_get_layer_property(const char *name, const struct loader_layer_list *layer_list) {
906 for (uint32_t i = 0; i < layer_list->count; i++) {
907 const VkLayerProperties *item = &layer_list->list[i].info;
908 if (strcmp(name, item->layerName) == 0) return &layer_list->list[i];
913 // Get the next unused layer property in the list. Init the property to zero.
914 static struct loader_layer_properties *loader_get_next_layer_property(const struct loader_instance *inst,
915 struct loader_layer_list *layer_list) {
916 if (layer_list->capacity == 0) {
918 loader_instance_heap_alloc(inst, sizeof(struct loader_layer_properties) * 64, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
919 if (layer_list->list == NULL) {
920 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
921 "loader_get_next_layer_property: Out of memory can "
922 "not add any layer properties to list");
925 memset(layer_list->list, 0, sizeof(struct loader_layer_properties) * 64);
926 layer_list->capacity = sizeof(struct loader_layer_properties) * 64;
929 // Ensure enough room to add an entry
930 if ((layer_list->count + 1) * sizeof(struct loader_layer_properties) > layer_list->capacity) {
931 void *new_ptr = loader_instance_heap_realloc(inst, layer_list->list, layer_list->capacity, layer_list->capacity * 2,
932 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
933 if (NULL == new_ptr) {
934 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, "loader_get_next_layer_property: realloc failed for layer list");
937 layer_list->list = new_ptr;
938 layer_list->capacity *= 2;
942 return &(layer_list->list[layer_list->count - 1]);
945 // Remove all layer properties entries from the list
946 void loader_delete_layer_properties(const struct loader_instance *inst, struct loader_layer_list *layer_list) {
948 struct loader_device_extension_list *dev_ext_list;
949 struct loader_dev_ext_props *ext_props;
950 if (!layer_list) return;
952 for (i = 0; i < layer_list->count; i++) {
953 if (NULL != layer_list->list[i].component_layer_names) {
954 loader_instance_heap_free(inst, layer_list->list[i].component_layer_names);
955 layer_list->list[i].component_layer_names = NULL;
957 loader_destroy_generic_list(inst, (struct loader_generic_list *)&layer_list->list[i].instance_extension_list);
958 dev_ext_list = &layer_list->list[i].device_extension_list;
959 if (dev_ext_list->capacity > 0 && NULL != dev_ext_list->list) {
960 for (j = 0; j < dev_ext_list->count; j++) {
961 ext_props = &dev_ext_list->list[j];
962 if (ext_props->entrypoint_count > 0) {
963 for (k = 0; k < ext_props->entrypoint_count; k++) {
964 loader_instance_heap_free(inst, ext_props->entrypoints[k]);
966 loader_instance_heap_free(inst, ext_props->entrypoints);
970 loader_destroy_generic_list(inst, (struct loader_generic_list *)dev_ext_list);
972 layer_list->count = 0;
974 if (layer_list->capacity > 0) {
975 layer_list->capacity = 0;
976 loader_instance_heap_free(inst, layer_list->list);
980 static VkResult loader_add_instance_extensions(const struct loader_instance *inst,
981 const PFN_vkEnumerateInstanceExtensionProperties fp_get_props, const char *lib_name,
982 struct loader_extension_list *ext_list) {
983 uint32_t i, count = 0;
984 VkExtensionProperties *ext_props;
985 VkResult res = VK_SUCCESS;
988 // No EnumerateInstanceExtensionProperties defined
992 res = fp_get_props(NULL, &count, NULL);
993 if (res != VK_SUCCESS) {
994 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
995 "loader_add_instance_extensions: Error getting Instance "
996 "extension count from %s",
1002 // No ExtensionProperties to report
1006 ext_props = loader_stack_alloc(count * sizeof(VkExtensionProperties));
1007 if (NULL == ext_props) {
1008 res = VK_ERROR_OUT_OF_HOST_MEMORY;
1012 res = fp_get_props(NULL, &count, ext_props);
1013 if (res != VK_SUCCESS) {
1014 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1015 "loader_add_instance_extensions: Error getting Instance "
1016 "extensions from %s",
1021 for (i = 0; i < count; i++) {
1022 char spec_version[64];
1024 bool ext_unsupported = wsi_unsupported_instance_extension(&ext_props[i]);
1025 if (!ext_unsupported) {
1026 (void)snprintf(spec_version, sizeof(spec_version), "%d.%d.%d", VK_VERSION_MAJOR(ext_props[i].specVersion),
1027 VK_VERSION_MINOR(ext_props[i].specVersion), VK_VERSION_PATCH(ext_props[i].specVersion));
1028 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Instance Extension: %s (%s) version %s", ext_props[i].extensionName,
1029 lib_name, spec_version);
1031 res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
1032 if (res != VK_SUCCESS) {
1033 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1034 "loader_add_instance_extensions: Failed to add %s "
1035 "to Instance extension list",
1046 // Initialize ext_list with the physical device extensions.
1047 // The extension properties are passed as inputs in count and ext_props.
1048 static VkResult loader_init_device_extensions(const struct loader_instance *inst, struct loader_physical_device_term *phys_dev_term,
1049 uint32_t count, VkExtensionProperties *ext_props,
1050 struct loader_extension_list *ext_list) {
1054 res = loader_init_generic_list(inst, (struct loader_generic_list *)ext_list, sizeof(VkExtensionProperties));
1055 if (VK_SUCCESS != res) {
1059 for (i = 0; i < count; i++) {
1060 char spec_version[64];
1061 (void)snprintf(spec_version, sizeof(spec_version), "%d.%d.%d", VK_VERSION_MAJOR(ext_props[i].specVersion),
1062 VK_VERSION_MINOR(ext_props[i].specVersion), VK_VERSION_PATCH(ext_props[i].specVersion));
1063 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Device Extension: %s (%s) version %s", ext_props[i].extensionName,
1064 phys_dev_term->this_icd_term->scanned_icd->lib_name, spec_version);
1065 res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
1066 if (res != VK_SUCCESS) return res;
1072 VkResult loader_add_device_extensions(const struct loader_instance *inst,
1073 PFN_vkEnumerateDeviceExtensionProperties fpEnumerateDeviceExtensionProperties,
1074 VkPhysicalDevice physical_device, const char *lib_name,
1075 struct loader_extension_list *ext_list) {
1078 VkExtensionProperties *ext_props;
1080 res = fpEnumerateDeviceExtensionProperties(physical_device, NULL, &count, NULL);
1081 if (res == VK_SUCCESS && count > 0) {
1082 ext_props = loader_stack_alloc(count * sizeof(VkExtensionProperties));
1084 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1085 "loader_add_device_extensions: Failed to allocate space"
1086 " for device extension properties.");
1087 return VK_ERROR_OUT_OF_HOST_MEMORY;
1089 res = fpEnumerateDeviceExtensionProperties(physical_device, NULL, &count, ext_props);
1090 if (res != VK_SUCCESS) {
1093 for (i = 0; i < count; i++) {
1094 char spec_version[64];
1095 (void)snprintf(spec_version, sizeof(spec_version), "%d.%d.%d", VK_VERSION_MAJOR(ext_props[i].specVersion),
1096 VK_VERSION_MINOR(ext_props[i].specVersion), VK_VERSION_PATCH(ext_props[i].specVersion));
1097 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Device Extension: %s (%s) version %s", ext_props[i].extensionName,
1098 lib_name, spec_version);
1099 res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
1100 if (res != VK_SUCCESS) {
1105 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1106 "loader_add_device_extensions: Error getting physical "
1107 "device extension info count from library %s",
1115 VkResult loader_init_generic_list(const struct loader_instance *inst, struct loader_generic_list *list_info, size_t element_size) {
1116 size_t capacity = 32 * element_size;
1117 list_info->count = 0;
1118 list_info->capacity = 0;
1119 list_info->list = loader_instance_heap_alloc(inst, capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1120 if (list_info->list == NULL) {
1121 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1122 "loader_init_generic_list: Failed to allocate space "
1123 "for generic list");
1124 return VK_ERROR_OUT_OF_HOST_MEMORY;
1126 memset(list_info->list, 0, capacity);
1127 list_info->capacity = capacity;
1131 void loader_destroy_generic_list(const struct loader_instance *inst, struct loader_generic_list *list) {
1132 loader_instance_heap_free(inst, list->list);
1137 // Append non-duplicate extension properties defined in props to the given ext_list.
1138 // Return - Vk_SUCCESS on success
1139 VkResult loader_add_to_ext_list(const struct loader_instance *inst, struct loader_extension_list *ext_list,
1140 uint32_t prop_list_count, const VkExtensionProperties *props) {
1142 const VkExtensionProperties *cur_ext;
1144 if (ext_list->list == NULL || ext_list->capacity == 0) {
1145 VkResult res = loader_init_generic_list(inst, (struct loader_generic_list *)ext_list, sizeof(VkExtensionProperties));
1146 if (VK_SUCCESS != res) {
1151 for (i = 0; i < prop_list_count; i++) {
1152 cur_ext = &props[i];
1154 // look for duplicates
1155 if (has_vk_extension_property(cur_ext, ext_list)) {
1159 // add to list at end
1160 // check for enough capacity
1161 if (ext_list->count * sizeof(VkExtensionProperties) >= ext_list->capacity) {
1162 void *new_ptr = loader_instance_heap_realloc(inst, ext_list->list, ext_list->capacity, ext_list->capacity * 2,
1163 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1164 if (new_ptr == NULL) {
1165 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1166 "loader_add_to_ext_list: Failed to reallocate "
1167 "space for extension list");
1168 return VK_ERROR_OUT_OF_HOST_MEMORY;
1170 ext_list->list = new_ptr;
1173 ext_list->capacity *= 2;
1176 memcpy(&ext_list->list[ext_list->count], cur_ext, sizeof(VkExtensionProperties));
1182 // Append one extension property defined in props with entrypoints defined in entries to the given
1183 // ext_list. Do not append if a duplicate.
1184 // Return - Vk_SUCCESS on success
1185 VkResult loader_add_to_dev_ext_list(const struct loader_instance *inst, struct loader_device_extension_list *ext_list,
1186 const VkExtensionProperties *props, uint32_t entry_count, char **entrys) {
1188 if (ext_list->list == NULL || ext_list->capacity == 0) {
1189 VkResult res = loader_init_generic_list(inst, (struct loader_generic_list *)ext_list, sizeof(struct loader_dev_ext_props));
1190 if (VK_SUCCESS != res) {
1195 // look for duplicates
1196 if (has_vk_dev_ext_property(props, ext_list)) {
1200 idx = ext_list->count;
1201 // add to list at end
1202 // check for enough capacity
1203 if (idx * sizeof(struct loader_dev_ext_props) >= ext_list->capacity) {
1204 void *new_ptr = loader_instance_heap_realloc(inst, ext_list->list, ext_list->capacity, ext_list->capacity * 2,
1205 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1207 if (NULL == new_ptr) {
1208 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1209 "loader_add_to_dev_ext_list: Failed to reallocate space for device extension list");
1210 return VK_ERROR_OUT_OF_HOST_MEMORY;
1212 ext_list->list = new_ptr;
1215 ext_list->capacity *= 2;
1218 memcpy(&ext_list->list[idx].props, props, sizeof(*props));
1219 ext_list->list[idx].entrypoint_count = entry_count;
1220 if (entry_count == 0) {
1221 ext_list->list[idx].entrypoints = NULL;
1223 ext_list->list[idx].entrypoints =
1224 loader_instance_heap_alloc(inst, sizeof(char *) * entry_count, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1225 if (ext_list->list[idx].entrypoints == NULL) {
1226 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1227 "loader_add_to_dev_ext_list: Failed to allocate space "
1228 "for device extension entrypoint list in list %d",
1230 ext_list->list[idx].entrypoint_count = 0;
1231 return VK_ERROR_OUT_OF_HOST_MEMORY;
1233 for (uint32_t i = 0; i < entry_count; i++) {
1234 ext_list->list[idx].entrypoints[i] =
1235 loader_instance_heap_alloc(inst, strlen(entrys[i]) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1236 if (ext_list->list[idx].entrypoints[i] == NULL) {
1237 for (uint32_t j = 0; j < i; j++) {
1238 loader_instance_heap_free(inst, ext_list->list[idx].entrypoints[j]);
1240 loader_instance_heap_free(inst, ext_list->list[idx].entrypoints);
1241 ext_list->list[idx].entrypoint_count = 0;
1242 ext_list->list[idx].entrypoints = NULL;
1243 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1244 "loader_add_to_dev_ext_list: Failed to allocate space "
1245 "for device extension entrypoint %d name",
1247 return VK_ERROR_OUT_OF_HOST_MEMORY;
1249 strcpy(ext_list->list[idx].entrypoints[i], entrys[i]);
1257 // Prototype of loader_add_meta_layer function since we use it in the loader_add_implicit_layer, but can also
1258 // call loader_add_implicit_layer from loader_add_meta_layer.
1259 bool loader_add_meta_layer(const struct loader_instance *inst, const struct loader_layer_properties *prop,
1260 struct loader_layer_list *target_list, struct loader_layer_list *expanded_target_list,
1261 const struct loader_layer_list *source_list);
1263 // Search the given layer list for a list matching the given VkLayerProperties
1264 bool has_vk_layer_property(const VkLayerProperties *vk_layer_prop, const struct loader_layer_list *list) {
1265 for (uint32_t i = 0; i < list->count; i++) {
1266 if (strcmp(vk_layer_prop->layerName, list->list[i].info.layerName) == 0) return true;
1271 // Search the given layer list for a layer matching the given name
1272 bool has_layer_name(const char *name, const struct loader_layer_list *list) {
1273 for (uint32_t i = 0; i < list->count; i++) {
1274 if (strcmp(name, list->list[i].info.layerName) == 0) return true;
1279 // Search the given search_list for any layers in the props list. Add these to the
1280 // output layer_list. Don't add duplicates to the output layer_list.
1281 static VkResult loader_add_layer_names_to_list(const struct loader_instance *inst, struct loader_layer_list *output_list,
1282 struct loader_layer_list *expanded_output_list, uint32_t name_count,
1283 const char *const *names, const struct loader_layer_list *source_list) {
1284 struct loader_layer_properties *layer_prop;
1285 VkResult err = VK_SUCCESS;
1287 for (uint32_t i = 0; i < name_count; i++) {
1288 const char *source_name = names[i];
1289 layer_prop = loader_get_layer_property(source_name, source_list);
1290 if (NULL == layer_prop) {
1291 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1292 "loader_add_layer_names_to_list: Unable to find layer"
1295 err = VK_ERROR_LAYER_NOT_PRESENT;
1299 // If not a meta-layer, simply add it.
1300 if (0 == (layer_prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) {
1301 if (!has_vk_layer_property(&layer_prop->info, output_list)) {
1302 loader_add_to_layer_list(inst, output_list, 1, layer_prop);
1304 if (!has_vk_layer_property(&layer_prop->info, expanded_output_list)) {
1305 loader_add_to_layer_list(inst, expanded_output_list, 1, layer_prop);
1308 if (!has_vk_layer_property(&layer_prop->info, output_list) ||
1309 !has_vk_layer_property(&layer_prop->info, expanded_output_list)) {
1310 loader_add_meta_layer(inst, layer_prop, output_list, expanded_output_list, source_list);
1318 // Manage lists of VkLayerProperties
1319 static bool loader_init_layer_list(const struct loader_instance *inst, struct loader_layer_list *list) {
1320 list->capacity = 32 * sizeof(struct loader_layer_properties);
1321 list->list = loader_instance_heap_alloc(inst, list->capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1322 if (list->list == NULL) {
1325 memset(list->list, 0, list->capacity);
1330 void loader_destroy_layer_list(const struct loader_instance *inst, struct loader_device *device,
1331 struct loader_layer_list *layer_list) {
1333 loader_device_heap_free(device, layer_list->list);
1335 loader_instance_heap_free(inst, layer_list->list);
1337 layer_list->count = 0;
1338 layer_list->capacity = 0;
1341 // Append non-duplicate layer properties defined in prop_list to the given layer_info list
1342 VkResult loader_add_to_layer_list(const struct loader_instance *inst, struct loader_layer_list *list, uint32_t prop_list_count,
1343 const struct loader_layer_properties *props) {
1345 struct loader_layer_properties *layer;
1347 if (list->list == NULL || list->capacity == 0) {
1348 loader_init_layer_list(inst, list);
1351 if (list->list == NULL) return VK_SUCCESS;
1353 for (i = 0; i < prop_list_count; i++) {
1354 layer = (struct loader_layer_properties *)&props[i];
1356 // Look for duplicates, and skip
1357 if (has_vk_layer_property(&layer->info, list)) {
1361 // Check for enough capacity
1362 if (((list->count + 1) * sizeof(struct loader_layer_properties)) >= list->capacity) {
1363 size_t new_capacity = list->capacity * 2;
1365 loader_instance_heap_realloc(inst, list->list, list->capacity, new_capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1366 if (NULL == new_ptr) {
1367 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1368 "loader_add_to_layer_list: Realloc failed for when attempting to add new layer");
1369 return VK_ERROR_OUT_OF_HOST_MEMORY;
1371 list->list = new_ptr;
1372 list->capacity = new_capacity;
1375 memcpy(&list->list[list->count], layer, sizeof(struct loader_layer_properties));
1382 // Check the individual implicit layer for the enable/disable environment variable settings. Only add it after
1383 // every check has passed indicating it should be used.
1384 static void loader_add_implicit_layer(const struct loader_instance *inst, const struct loader_layer_properties *prop,
1385 struct loader_layer_list *target_list, struct loader_layer_list *expanded_target_list,
1386 const struct loader_layer_list *source_list) {
1387 bool enable = loader_is_implicit_layer_enabled(inst, prop);
1389 if (0 == (prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) {
1390 if (NULL != target_list && !has_vk_layer_property(&prop->info, target_list)) {
1391 loader_add_to_layer_list(inst, target_list, 1, prop);
1393 if (NULL != expanded_target_list && !has_vk_layer_property(&prop->info, expanded_target_list)) {
1394 loader_add_to_layer_list(inst, expanded_target_list, 1, prop);
1397 if (!has_vk_layer_property(&prop->info, target_list) ||
1398 (NULL != expanded_target_list && !has_vk_layer_property(&prop->info, expanded_target_list))) {
1399 loader_add_meta_layer(inst, prop, target_list, expanded_target_list, source_list);
1405 // Add the component layers of a meta-layer to the active list of layers
1406 bool loader_add_meta_layer(const struct loader_instance *inst, const struct loader_layer_properties *prop,
1407 struct loader_layer_list *target_list, struct loader_layer_list *expanded_target_list,
1408 const struct loader_layer_list *source_list) {
1411 // We need to add all the individual component layers
1412 for (uint32_t comp_layer = 0; comp_layer < prop->num_component_layers; comp_layer++) {
1413 bool found_comp = false;
1414 const struct loader_layer_properties *search_prop =
1415 loader_get_layer_property(prop->component_layer_names[comp_layer], source_list);
1416 if (search_prop != NULL) {
1419 // If the component layer is itself an implicit layer, we need to do the implicit layer enable
1421 if (0 == (search_prop->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER)) {
1422 loader_add_implicit_layer(inst, search_prop, target_list, expanded_target_list, source_list);
1424 if (NULL != expanded_target_list && !has_vk_layer_property(&search_prop->info, expanded_target_list)) {
1425 loader_add_to_layer_list(inst, expanded_target_list, 1, search_prop);
1430 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
1431 "loader_add_meta_layer: Failed to find layer name %s component layer "
1433 search_prop->info.layerName, prop->component_layer_names[comp_layer]);
1438 // Add this layer to the overall target list (not the expanded one)
1439 if (found && !has_vk_layer_property(&prop->info, target_list)) {
1440 loader_add_to_layer_list(inst, target_list, 1, prop);
1446 // Search the source_list for any layer with a name that matches the given name and a type
1447 // that matches the given type. Add all matching layers to the target_list.
1448 // Do not add if found loader_layer_properties is already on the target_list.
1449 void loader_find_layer_name_add_list(const struct loader_instance *inst, const char *name, const enum layer_type_flags type_flags,
1450 const struct loader_layer_list *source_list, struct loader_layer_list *target_list,
1451 struct loader_layer_list *expanded_target_list) {
1453 for (uint32_t i = 0; i < source_list->count; i++) {
1454 struct loader_layer_properties *source_prop = &source_list->list[i];
1455 if (0 == strcmp(source_prop->info.layerName, name) && (source_prop->type_flags & type_flags) == type_flags) {
1456 // If not a meta-layer, simply add it.
1457 if (0 == (source_prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) {
1458 if (NULL != target_list && !has_vk_layer_property(&source_prop->info, target_list) &&
1459 VK_SUCCESS == loader_add_to_layer_list(inst, target_list, 1, source_prop)) {
1462 if (NULL != expanded_target_list && !has_vk_layer_property(&source_prop->info, expanded_target_list) &&
1463 VK_SUCCESS == loader_add_to_layer_list(inst, expanded_target_list, 1, source_prop)) {
1467 found = loader_add_meta_layer(inst, source_prop, target_list, expanded_target_list, source_list);
1472 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
1473 "loader_find_layer_name_add_list: Failed to find layer name %s to activate", name);
1477 static VkExtensionProperties *get_extension_property(const char *name, const struct loader_extension_list *list) {
1478 for (uint32_t i = 0; i < list->count; i++) {
1479 if (strcmp(name, list->list[i].extensionName) == 0) return &list->list[i];
1484 static VkExtensionProperties *get_dev_extension_property(const char *name, const struct loader_device_extension_list *list) {
1485 for (uint32_t i = 0; i < list->count; i++) {
1486 if (strcmp(name, list->list[i].props.extensionName) == 0) return &list->list[i].props;
1491 // For Instance extensions implemented within the loader (i.e. DEBUG_REPORT
1492 // the extension must provide two entry points for the loader to use:
1493 // - "trampoline" entry point - this is the address returned by GetProcAddr
1494 // and will always do what's necessary to support a
1496 // - "terminator" function - this function will be put at the end of the
1497 // instance chain and will contain the necessary logic
1498 // to call / process the extension for the appropriate
1499 // ICDs that are available.
1500 // There is no generic mechanism for including these functions, the references
1501 // must be placed into the appropriate loader entry points.
1502 // GetInstanceProcAddr: call extension GetInstanceProcAddr to check for GetProcAddr
1504 // loader_coalesce_extensions(void) - add extension records to the list of global
1505 // extension available to the app.
1506 // instance_disp - add function pointer for terminator function
1508 // The extension itself should be in a separate file that will be linked directly
1510 VkResult loader_get_icd_loader_instance_extensions(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list,
1511 struct loader_extension_list *inst_exts) {
1512 struct loader_extension_list icd_exts;
1513 VkResult res = VK_SUCCESS;
1515 bool filter_extensions = true;
1517 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Build ICD instance extension list");
1519 // Check if a user wants to disable the instance extension filtering behavior
1520 env_value = loader_getenv("VK_LOADER_DISABLE_INST_EXT_FILTER", inst);
1521 if (NULL != env_value && atoi(env_value) != 0) {
1522 filter_extensions = false;
1524 loader_free_getenv(env_value, inst);
1526 // traverse scanned icd list adding non-duplicate extensions to the list
1527 for (uint32_t i = 0; i < icd_tramp_list->count; i++) {
1528 res = loader_init_generic_list(inst, (struct loader_generic_list *)&icd_exts, sizeof(VkExtensionProperties));
1529 if (VK_SUCCESS != res) {
1532 res = loader_add_instance_extensions(inst, icd_tramp_list->scanned_list[i].EnumerateInstanceExtensionProperties,
1533 icd_tramp_list->scanned_list[i].lib_name, &icd_exts);
1534 if (VK_SUCCESS == res) {
1535 if (filter_extensions) {
1536 // Remove any extensions not recognized by the loader
1537 for (int32_t j = 0; j < (int32_t)icd_exts.count; j++) {
1538 // See if the extension is in the list of supported extensions
1540 for (uint32_t k = 0; LOADER_INSTANCE_EXTENSIONS[k] != NULL; k++) {
1541 if (strcmp(icd_exts.list[j].extensionName, LOADER_INSTANCE_EXTENSIONS[k]) == 0) {
1547 // If it isn't in the list, remove it
1549 for (uint32_t k = j + 1; k < icd_exts.count; k++) {
1550 icd_exts.list[k - 1] = icd_exts.list[k];
1558 res = loader_add_to_ext_list(inst, inst_exts, icd_exts.count, icd_exts.list);
1560 loader_destroy_generic_list(inst, (struct loader_generic_list *)&icd_exts);
1561 if (VK_SUCCESS != res) {
1566 // Traverse loader's extensions, adding non-duplicate extensions to the list
1567 debug_report_add_instance_extensions(inst, inst_exts);
1573 struct loader_icd_term *loader_get_icd_and_device(const VkDevice device, struct loader_device **found_dev, uint32_t *icd_index) {
1575 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
1577 for (struct loader_icd_term *icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) {
1578 for (struct loader_device *dev = icd_term->logical_device_list; dev; dev = dev->next)
1579 // Value comparison of device prevents object wrapping by layers
1580 if (loader_get_dispatch(dev->icd_device) == loader_get_dispatch(device) ||
1581 loader_get_dispatch(dev->chain_device) == loader_get_dispatch(device)) {
1583 if (NULL != icd_index) {
1594 void loader_destroy_logical_device(const struct loader_instance *inst, struct loader_device *dev,
1595 const VkAllocationCallbacks *pAllocator) {
1597 dev->alloc_callbacks = *pAllocator;
1599 if (NULL != dev->expanded_activated_layer_list.list) {
1600 loader_deactivate_layers(inst, dev, &dev->expanded_activated_layer_list);
1602 if (NULL != dev->app_activated_layer_list.list) {
1603 loader_destroy_layer_list(inst, dev, &dev->app_activated_layer_list);
1605 loader_device_heap_free(dev, dev);
1608 struct loader_device *loader_create_logical_device(const struct loader_instance *inst, const VkAllocationCallbacks *pAllocator) {
1609 struct loader_device *new_dev;
1610 #if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
1614 new_dev = (struct loader_device *)pAllocator->pfnAllocation(pAllocator->pUserData, sizeof(struct loader_device),
1615 sizeof(int *), VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
1618 new_dev = (struct loader_device *)malloc(sizeof(struct loader_device));
1622 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1623 "loader_create_logical_device: Failed to alloc struct "
1628 memset(new_dev, 0, sizeof(struct loader_device));
1630 new_dev->alloc_callbacks = *pAllocator;
1636 void loader_add_logical_device(const struct loader_instance *inst, struct loader_icd_term *icd_term, struct loader_device *dev) {
1637 dev->next = icd_term->logical_device_list;
1638 icd_term->logical_device_list = dev;
1641 void loader_remove_logical_device(const struct loader_instance *inst, struct loader_icd_term *icd_term,
1642 struct loader_device *found_dev, const VkAllocationCallbacks *pAllocator) {
1643 struct loader_device *dev, *prev_dev;
1645 if (!icd_term || !found_dev) return;
1648 dev = icd_term->logical_device_list;
1649 while (dev && dev != found_dev) {
1655 prev_dev->next = found_dev->next;
1657 icd_term->logical_device_list = found_dev->next;
1658 loader_destroy_logical_device(inst, found_dev, pAllocator);
1661 static void loader_icd_destroy(struct loader_instance *ptr_inst, struct loader_icd_term *icd_term,
1662 const VkAllocationCallbacks *pAllocator) {
1663 ptr_inst->total_icd_count--;
1664 for (struct loader_device *dev = icd_term->logical_device_list; dev;) {
1665 struct loader_device *next_dev = dev->next;
1666 loader_destroy_logical_device(ptr_inst, dev, pAllocator);
1670 loader_instance_heap_free(ptr_inst, icd_term);
1673 static struct loader_icd_term *loader_icd_create(const struct loader_instance *inst) {
1674 struct loader_icd_term *icd_term;
1676 icd_term = loader_instance_heap_alloc(inst, sizeof(struct loader_icd_term), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1681 memset(icd_term, 0, sizeof(struct loader_icd_term));
1686 static struct loader_icd_term *loader_icd_add(struct loader_instance *ptr_inst, const struct loader_scanned_icd *scanned_icd) {
1687 struct loader_icd_term *icd_term;
1689 icd_term = loader_icd_create(ptr_inst);
1694 icd_term->scanned_icd = scanned_icd;
1695 icd_term->this_instance = ptr_inst;
1697 // Prepend to the list
1698 icd_term->next = ptr_inst->icd_terms;
1699 ptr_inst->icd_terms = icd_term;
1700 ptr_inst->total_icd_count++;
1705 // Determine the ICD interface version to use.
1707 // @param pVersion Output parameter indicating which version to use or 0 if
1708 // the negotiation API is not supported by the ICD
1709 // @return bool indicating true if the selected interface version is supported
1710 // by the loader, false indicates the version is not supported
1711 bool loader_get_icd_interface_version(PFN_vkNegotiateLoaderICDInterfaceVersion fp_negotiate_icd_version, uint32_t *pVersion) {
1712 if (fp_negotiate_icd_version == NULL) {
1713 // ICD does not support the negotiation API, it supports version 0 or 1
1714 // calling code must determine if it is version 0 or 1
1717 // ICD supports the negotiation API, so call it with the loader's
1718 // latest version supported
1719 *pVersion = CURRENT_LOADER_ICD_INTERFACE_VERSION;
1720 VkResult result = fp_negotiate_icd_version(pVersion);
1722 if (result == VK_ERROR_INCOMPATIBLE_DRIVER) {
1723 // ICD no longer supports the loader's latest interface version so
1724 // fail loading the ICD
1729 #if MIN_SUPPORTED_LOADER_ICD_INTERFACE_VERSION > 0
1730 if (*pVersion < MIN_SUPPORTED_LOADER_ICD_INTERFACE_VERSION) {
1731 // Loader no longer supports the ICD's latest interface version so fail
1739 void loader_scanned_icd_clear(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list) {
1740 if (0 != icd_tramp_list->capacity) {
1741 for (uint32_t i = 0; i < icd_tramp_list->count; i++) {
1742 loader_platform_close_library(icd_tramp_list->scanned_list[i].handle);
1743 loader_instance_heap_free(inst, icd_tramp_list->scanned_list[i].lib_name);
1745 loader_instance_heap_free(inst, icd_tramp_list->scanned_list);
1746 icd_tramp_list->capacity = 0;
1747 icd_tramp_list->count = 0;
1748 icd_tramp_list->scanned_list = NULL;
1752 static VkResult loader_scanned_icd_init(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list) {
1753 VkResult err = VK_SUCCESS;
1754 loader_scanned_icd_clear(inst, icd_tramp_list);
1755 icd_tramp_list->capacity = 8 * sizeof(struct loader_scanned_icd);
1756 icd_tramp_list->scanned_list = loader_instance_heap_alloc(inst, icd_tramp_list->capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1757 if (NULL == icd_tramp_list->scanned_list) {
1758 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1759 "loader_scanned_icd_init: Realloc failed for layer list when "
1760 "attempting to add new layer");
1761 err = VK_ERROR_OUT_OF_HOST_MEMORY;
1766 static VkResult loader_scanned_icd_add(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list,
1767 const char *filename, uint32_t api_version) {
1768 loader_platform_dl_handle handle;
1769 PFN_vkCreateInstance fp_create_inst;
1770 PFN_vkEnumerateInstanceExtensionProperties fp_get_inst_ext_props;
1771 PFN_vkGetInstanceProcAddr fp_get_proc_addr;
1772 PFN_GetPhysicalDeviceProcAddr fp_get_phys_dev_proc_addr = NULL;
1773 PFN_vkNegotiateLoaderICDInterfaceVersion fp_negotiate_icd_version;
1774 struct loader_scanned_icd *new_scanned_icd;
1775 uint32_t interface_vers;
1776 VkResult res = VK_SUCCESS;
1778 // TODO implement smarter opening/closing of libraries. For now this
1779 // function leaves libraries open and the scanned_icd_clear closes them
1780 handle = loader_platform_open_library(filename);
1781 if (NULL == handle) {
1782 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, loader_platform_open_library_error(filename));
1786 // Get and settle on an ICD interface version
1787 fp_negotiate_icd_version = loader_platform_get_proc_address(handle, "vk_icdNegotiateLoaderICDInterfaceVersion");
1789 if (!loader_get_icd_interface_version(fp_negotiate_icd_version, &interface_vers)) {
1790 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1791 "loader_scanned_icd_add: ICD %s doesn't support interface"
1792 " version compatible with loader, skip this ICD.",
1797 fp_get_proc_addr = loader_platform_get_proc_address(handle, "vk_icdGetInstanceProcAddr");
1798 if (NULL == fp_get_proc_addr) {
1799 assert(interface_vers == 0);
1800 // Use deprecated interface from version 0
1801 fp_get_proc_addr = loader_platform_get_proc_address(handle, "vkGetInstanceProcAddr");
1802 if (NULL == fp_get_proc_addr) {
1803 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1804 "loader_scanned_icd_add: Attempt to retrieve either "
1805 "\'vkGetInstanceProcAddr\' or "
1806 "\'vk_icdGetInstanceProcAddr\' from ICD %s failed.",
1810 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
1811 "loader_scanned_icd_add: Using deprecated ICD "
1812 "interface of \'vkGetInstanceProcAddr\' instead of "
1813 "\'vk_icdGetInstanceProcAddr\' for ICD %s",
1816 fp_create_inst = loader_platform_get_proc_address(handle, "vkCreateInstance");
1817 if (NULL == fp_create_inst) {
1818 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1819 "loader_scanned_icd_add: Failed querying "
1820 "\'vkCreateInstance\' via dlsym/loadlibrary for "
1825 fp_get_inst_ext_props = loader_platform_get_proc_address(handle, "vkEnumerateInstanceExtensionProperties");
1826 if (NULL == fp_get_inst_ext_props) {
1827 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1828 "loader_scanned_icd_add: Could not get \'vkEnumerate"
1829 "InstanceExtensionProperties\' via dlsym/loadlibrary "
1835 // Use newer interface version 1 or later
1836 if (interface_vers == 0) {
1840 fp_create_inst = (PFN_vkCreateInstance)fp_get_proc_addr(NULL, "vkCreateInstance");
1841 if (NULL == fp_create_inst) {
1842 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1843 "loader_scanned_icd_add: Could not get "
1844 "\'vkCreateInstance\' via \'vk_icdGetInstanceProcAddr\'"
1849 fp_get_inst_ext_props =
1850 (PFN_vkEnumerateInstanceExtensionProperties)fp_get_proc_addr(NULL, "vkEnumerateInstanceExtensionProperties");
1851 if (NULL == fp_get_inst_ext_props) {
1852 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1853 "loader_scanned_icd_add: Could not get \'vkEnumerate"
1854 "InstanceExtensionProperties\' via "
1855 "\'vk_icdGetInstanceProcAddr\' for ICD %s",
1859 fp_get_phys_dev_proc_addr = loader_platform_get_proc_address(handle, "vk_icdGetPhysicalDeviceProcAddr");
1862 // check for enough capacity
1863 if ((icd_tramp_list->count * sizeof(struct loader_scanned_icd)) >= icd_tramp_list->capacity) {
1864 void *new_ptr = loader_instance_heap_realloc(inst, icd_tramp_list->scanned_list, icd_tramp_list->capacity,
1865 icd_tramp_list->capacity * 2, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1866 if (NULL == new_ptr) {
1867 res = VK_ERROR_OUT_OF_HOST_MEMORY;
1868 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1869 "loader_scanned_icd_add: Realloc failed on icd library list for ICD %s", filename);
1872 icd_tramp_list->scanned_list = new_ptr;
1875 icd_tramp_list->capacity *= 2;
1878 new_scanned_icd = &(icd_tramp_list->scanned_list[icd_tramp_list->count]);
1879 new_scanned_icd->handle = handle;
1880 new_scanned_icd->api_version = api_version;
1881 new_scanned_icd->GetInstanceProcAddr = fp_get_proc_addr;
1882 new_scanned_icd->GetPhysicalDeviceProcAddr = fp_get_phys_dev_proc_addr;
1883 new_scanned_icd->EnumerateInstanceExtensionProperties = fp_get_inst_ext_props;
1884 new_scanned_icd->CreateInstance = fp_create_inst;
1885 new_scanned_icd->interface_version = interface_vers;
1887 new_scanned_icd->lib_name = (char *)loader_instance_heap_alloc(inst, strlen(filename) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1888 if (NULL == new_scanned_icd->lib_name) {
1889 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, "loader_scanned_icd_add: Out of memory can't add ICD %s", filename);
1890 res = VK_ERROR_OUT_OF_HOST_MEMORY;
1893 strcpy(new_scanned_icd->lib_name, filename);
1894 icd_tramp_list->count++;
1901 static void loader_debug_init(void) {
1904 if (g_loader_debug > 0) return;
1908 // Parse comma-separated debug options
1909 orig = env = loader_getenv("VK_LOADER_DEBUG", NULL);
1911 char *p = strchr(env, ',');
1920 if (strncmp(env, "all", len) == 0) {
1921 g_loader_debug = ~0u;
1922 g_loader_log_msgs = ~0u;
1923 } else if (strncmp(env, "warn", len) == 0) {
1924 g_loader_debug |= LOADER_WARN_BIT;
1925 g_loader_log_msgs |= VK_DEBUG_REPORT_WARNING_BIT_EXT;
1926 } else if (strncmp(env, "info", len) == 0) {
1927 g_loader_debug |= LOADER_INFO_BIT;
1928 g_loader_log_msgs |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT;
1929 } else if (strncmp(env, "perf", len) == 0) {
1930 g_loader_debug |= LOADER_PERF_BIT;
1931 g_loader_log_msgs |= VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
1932 } else if (strncmp(env, "error", len) == 0) {
1933 g_loader_debug |= LOADER_ERROR_BIT;
1934 g_loader_log_msgs |= VK_DEBUG_REPORT_ERROR_BIT_EXT;
1935 } else if (strncmp(env, "debug", len) == 0) {
1936 g_loader_debug |= LOADER_DEBUG_BIT;
1937 g_loader_log_msgs |= VK_DEBUG_REPORT_DEBUG_BIT_EXT;
1946 loader_free_getenv(orig, NULL);
1949 void loader_initialize(void) {
1950 // initialize mutexs
1951 loader_platform_thread_create_mutex(&loader_lock);
1952 loader_platform_thread_create_mutex(&loader_json_lock);
1954 // initialize logging
1955 loader_debug_init();
1957 // initial cJSON to use alloc callbacks
1958 cJSON_Hooks alloc_fns = {
1959 .malloc_fn = loader_instance_tls_heap_alloc, .free_fn = loader_instance_tls_heap_free,
1961 cJSON_InitHooks(&alloc_fns);
1964 struct loader_manifest_files {
1966 char **filename_list;
1969 void loader_release() {
1971 loader_platform_thread_delete_mutex(&loader_lock);
1972 loader_platform_thread_delete_mutex(&loader_json_lock);
1975 // Get next file or dirname given a string list or registry key path
1978 // A pointer to first char in the next path.
1979 // The next path (or NULL) in the list is returned in next_path.
1980 // Note: input string is modified in some cases. PASS IN A COPY!
1981 static char *loader_get_next_path(char *path) {
1985 if (path == NULL) return NULL;
1986 next = strchr(path, PATH_SEPARATOR);
1988 len = (uint32_t)strlen(path);
1998 // Given a path which is absolute or relative, expand the path if relative or
1999 // leave the path unmodified if absolute. The base path to prepend to relative
2000 // paths is given in rel_base.
2002 // @return - A string in out_fullpath of the full absolute path
2003 static void loader_expand_path(const char *path, const char *rel_base, size_t out_size, char *out_fullpath) {
2004 if (loader_platform_is_path_absolute(path)) {
2005 // do not prepend a base to an absolute path
2009 loader_platform_combine_path(out_fullpath, out_size, rel_base, path, NULL);
2012 // Given a filename (file) and a list of paths (dir), try to find an existing
2013 // file in the paths. If filename already is a path then no searching in the given paths.
2015 // @return - A string in out_fullpath of either the full path or file.
2016 static void loader_get_fullpath(const char *file, const char *dirs, size_t out_size, char *out_fullpath) {
2017 if (!loader_platform_is_path(file) && *dirs) {
2018 char *dirs_copy, *dir, *next_dir;
2020 dirs_copy = loader_stack_alloc(strlen(dirs) + 1);
2021 strcpy(dirs_copy, dirs);
2023 // find if file exists after prepending paths in given list
2024 for (dir = dirs_copy; *dir && (next_dir = loader_get_next_path(dir)); dir = next_dir) {
2025 loader_platform_combine_path(out_fullpath, out_size, dir, file, NULL);
2026 if (loader_platform_file_exists(out_fullpath)) {
2032 (void)snprintf(out_fullpath, out_size, "%s", file);
2035 // Read a JSON file into a buffer.
2037 // @return - A pointer to a cJSON object representing the JSON parse tree.
2038 // This returned buffer should be freed by caller.
2039 static VkResult loader_get_json(const struct loader_instance *inst, const char *filename, cJSON **json) {
2043 VkResult res = VK_SUCCESS;
2046 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, "loader_get_json: Received invalid JSON file");
2047 res = VK_ERROR_INITIALIZATION_FAILED;
2053 file = fopen(filename, "rb");
2055 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, "loader_get_json: Failed to open JSON file %s", filename);
2056 res = VK_ERROR_INITIALIZATION_FAILED;
2059 fseek(file, 0, SEEK_END);
2061 fseek(file, 0, SEEK_SET);
2062 json_buf = (char *)loader_stack_alloc(len + 1);
2063 if (json_buf == NULL) {
2064 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2065 "loader_get_json: Failed to allocate space for "
2066 "JSON file %s buffer of length %d",
2068 res = VK_ERROR_OUT_OF_HOST_MEMORY;
2071 if (fread(json_buf, sizeof(char), len, file) != len) {
2072 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, "loader_get_json: Failed to read JSON file %s.", filename);
2073 res = VK_ERROR_INITIALIZATION_FAILED;
2076 json_buf[len] = '\0';
2078 // Parse text from file
2079 *json = cJSON_Parse(json_buf);
2080 if (*json == NULL) {
2081 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2082 "loader_get_json: Failed to parse JSON file %s, "
2083 "this is usually because something ran out of "
2086 res = VK_ERROR_OUT_OF_HOST_MEMORY;
2098 // Do a deep copy of the loader_layer_properties structure.
2099 VkResult loader_copy_layer_properties(const struct loader_instance *inst, struct loader_layer_properties *dst,
2100 struct loader_layer_properties *src) {
2102 memcpy(dst, src, sizeof(*src));
2103 dst->instance_extension_list.list = loader_instance_heap_alloc(
2104 inst, sizeof(VkExtensionProperties) * src->instance_extension_list.count, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2105 if (NULL == dst->instance_extension_list.list) {
2106 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2107 "loader_copy_layer_properties: Failed to allocate space "
2108 "for instance extension list of size %d.",
2109 src->instance_extension_list.count);
2110 return VK_ERROR_OUT_OF_HOST_MEMORY;
2112 dst->instance_extension_list.capacity = sizeof(VkExtensionProperties) * src->instance_extension_list.count;
2113 memcpy(dst->instance_extension_list.list, src->instance_extension_list.list, dst->instance_extension_list.capacity);
2114 dst->device_extension_list.list = loader_instance_heap_alloc(
2115 inst, sizeof(struct loader_dev_ext_props) * src->device_extension_list.count, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2116 if (NULL == dst->device_extension_list.list) {
2117 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2118 "loader_copy_layer_properties: Failed to allocate space "
2119 "for device extension list of size %d.",
2120 src->device_extension_list.count);
2121 return VK_ERROR_OUT_OF_HOST_MEMORY;
2123 memset(dst->device_extension_list.list, 0, sizeof(struct loader_dev_ext_props) * src->device_extension_list.count);
2125 dst->device_extension_list.capacity = sizeof(struct loader_dev_ext_props) * src->device_extension_list.count;
2126 memcpy(dst->device_extension_list.list, src->device_extension_list.list, dst->device_extension_list.capacity);
2127 if (src->device_extension_list.count > 0 && src->device_extension_list.list->entrypoint_count > 0) {
2128 cnt = src->device_extension_list.list->entrypoint_count;
2129 dst->device_extension_list.list->entrypoints =
2130 loader_instance_heap_alloc(inst, sizeof(char *) * cnt, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2131 if (NULL == dst->device_extension_list.list->entrypoints) {
2132 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2133 "loader_copy_layer_properties: Failed to allocate space "
2134 "for device extension entrypoint list of size %d.",
2136 return VK_ERROR_OUT_OF_HOST_MEMORY;
2138 memset(dst->device_extension_list.list->entrypoints, 0, sizeof(char *) * cnt);
2140 for (i = 0; i < cnt; i++) {
2141 dst->device_extension_list.list->entrypoints[i] = loader_instance_heap_alloc(
2142 inst, strlen(src->device_extension_list.list->entrypoints[i]) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2143 if (NULL == dst->device_extension_list.list->entrypoints[i]) {
2144 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2145 "loader_copy_layer_properties: Failed to "
2146 "allocate space for device extension entrypoint "
2147 "%d name of length",
2149 return VK_ERROR_OUT_OF_HOST_MEMORY;
2151 strcpy(dst->device_extension_list.list->entrypoints[i], src->device_extension_list.list->entrypoints[i]);
2158 static bool loader_find_layer_name_list(const char *name, const struct loader_layer_list *layer_list) {
2159 if (NULL == layer_list) {
2162 for (uint32_t j = 0; j < layer_list->count; j++) {
2163 if (!strcmp(name, layer_list->list[j].info.layerName)) {
2170 bool loader_find_layer_name_array(const char *name, uint32_t layer_count, const char layer_list[][VK_MAX_EXTENSION_NAME_SIZE]) {
2171 if (!layer_list) return false;
2172 for (uint32_t j = 0; j < layer_count; j++)
2173 if (!strcmp(name, layer_list[j])) return true;
2177 const char *std_validation_str = "VK_LAYER_LUNARG_standard_validation";
2179 // Adds the legacy VK_LAYER_LUNARG_standard_validation as a meta-layer if it
2180 // fails to find it in the list already. This is usually an indication that a
2181 // newer loader is being used with an older layer set.
2182 static bool loader_add_legacy_std_val_layer(const struct loader_instance *inst, struct loader_layer_list *layer_instance_list) {
2184 bool success = true;
2185 struct loader_layer_properties *props = loader_get_next_layer_property(inst, layer_instance_list);
2186 const char std_validation_names[6][VK_MAX_EXTENSION_NAME_SIZE] = {
2187 "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation", "VK_LAYER_LUNARG_object_tracker",
2188 "VK_LAYER_LUNARG_core_validation", "VK_LAYER_GOOGLE_unique_objects"};
2189 uint32_t layer_count = sizeof(std_validation_names) / sizeof(std_validation_names[0]);
2191 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
2192 "Adding VK_LAYER_LUNARG_standard_validation using the loader legacy path. This is"
2195 if (NULL == props) {
2199 memset(props, 0, sizeof(struct loader_layer_properties));
2200 props->type_flags = VK_LAYER_TYPE_FLAG_INSTANCE_LAYER | VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER | VK_LAYER_TYPE_FLAG_META_LAYER;
2201 strncpy(props->info.description, "LunarG Standard Validation Layer", sizeof(props->info.description));
2202 props->info.implementationVersion = 1;
2203 strncpy(props->info.layerName, std_validation_str, sizeof(props->info.layerName));
2204 props->info.specVersion = VK_MAKE_VERSION(1, 0, VK_HEADER_VERSION);
2206 props->component_layer_names =
2207 loader_instance_heap_alloc(inst, sizeof(char[MAX_STRING_SIZE]) * layer_count, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2208 if (NULL == props->component_layer_names) {
2209 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2210 "Failed to allocate space for legacy VK_LAYER_LUNARG_standard_validation"
2211 " meta-layer component_layers information.");
2215 for (i = 0; i < layer_count; i++) {
2216 strncpy(props->component_layer_names[i], std_validation_names[i], MAX_STRING_SIZE - 1);
2217 props->component_layer_names[i][MAX_STRING_SIZE - 1] = '\0';
2222 if (!success && NULL != props && NULL != props->component_layer_names) {
2223 loader_instance_heap_free(inst, props->component_layer_names);
2224 props->component_layer_names = NULL;
2230 // Verify that all component layers in a meta-layer are valid.
2231 static bool verify_meta_layer_comp_layers(const struct loader_instance *inst, struct loader_layer_properties *prop,
2232 struct loader_layer_list *instance_layers) {
2233 bool success = true;
2234 const uint32_t expected_major = VK_VERSION_MAJOR(prop->info.specVersion);
2235 const uint32_t expected_minor = VK_VERSION_MINOR(prop->info.specVersion);
2237 for (uint32_t comp_layer = 0; comp_layer < prop->num_component_layers; comp_layer++) {
2238 if (!loader_find_layer_name_list(prop->component_layer_names[comp_layer], instance_layers)) {
2239 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2240 "Meta-layer %s can't find component layer %s at index %d."
2241 " Skipping this layer.",
2242 prop->info.layerName, prop->component_layer_names[comp_layer], comp_layer);
2246 struct loader_layer_properties *comp_prop =
2247 loader_get_layer_property(prop->component_layer_names[comp_layer], instance_layers);
2248 if (comp_prop == NULL) {
2249 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2250 "Meta-layer %s can't find property for component layer %s at index %d."
2251 " Skipping this layer.",
2252 prop->info.layerName, prop->component_layer_names[comp_layer], comp_layer);
2257 // Check the version of each layer, they need to at least match MAJOR and MINOR
2258 uint32_t cur_major = VK_VERSION_MAJOR(comp_prop->info.specVersion);
2259 uint32_t cur_minor = VK_VERSION_MINOR(comp_prop->info.specVersion);
2260 if (cur_major != expected_major || cur_minor != expected_minor) {
2261 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2262 "Meta-layer uses API version %d.%d, but component layer %d uses API "
2263 "version %d.%d. Skipping this layer.",
2264 expected_major, expected_minor, comp_layer, cur_major, cur_minor);
2269 // Make sure the layer isn't using it's own name
2270 if (!strcmp(prop->info.layerName, prop->component_layer_names[comp_layer])) {
2271 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2272 "Meta-layer %s lists itself in its component layer list at index %d."
2273 " Skipping this layer.",
2274 prop->info.layerName, comp_layer);
2278 if (comp_prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER) {
2279 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
2280 "verify_meta_layer_comp_layers: Adding meta-layer %s which also contains meta-layer %s",
2281 prop->info.layerName, comp_prop->info.layerName);
2283 // Make sure if the layer is using a meta-layer in its component list that we also verify that.
2284 if (!verify_meta_layer_comp_layers(inst, comp_prop, instance_layers)) {
2285 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2286 "Meta-layer %s component layer %s can not find all component layers."
2287 " Skipping this layer.",
2288 prop->info.layerName, prop->component_layer_names[comp_layer]);
2294 // Add any instance and device extensions from component layers to this layer
2295 // list, so that anyone querying extensions will only need to look at the meta-layer
2296 for (uint32_t ext = 0; ext < comp_prop->instance_extension_list.count; ext++) {
2297 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Meta-layer %s component layer %s adding instance extension %s",
2298 prop->info.layerName, prop->component_layer_names[comp_layer],
2299 comp_prop->instance_extension_list.list[ext].extensionName);
2300 if (!has_vk_extension_property(&comp_prop->instance_extension_list.list[ext], &prop->instance_extension_list)) {
2301 loader_add_to_ext_list(inst, &prop->instance_extension_list, 1, &comp_prop->instance_extension_list.list[ext]);
2305 for (uint32_t ext = 0; ext < comp_prop->device_extension_list.count; ext++) {
2306 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Meta-layer %s component layer %s adding device extension %s",
2307 prop->info.layerName, prop->component_layer_names[comp_layer],
2308 comp_prop->device_extension_list.list[ext].props.extensionName);
2309 if (!has_vk_dev_ext_property(&comp_prop->device_extension_list.list[ext].props, &prop->device_extension_list)) {
2310 loader_add_to_dev_ext_list(inst, &prop->device_extension_list,
2311 &comp_prop->device_extension_list.list[ext].props, 0, NULL);
2317 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "Meta-layer %s all %d component layers appear to be valid.",
2318 prop->info.layerName, prop->num_component_layers);
2323 // Verify that all meta-layers in a layer list are valid.
2324 static void verify_all_meta_layers(const struct loader_instance *inst, struct loader_layer_list *instance_layers) {
2325 for (int32_t i = 0; i < (int32_t)instance_layers->count; i++) {
2326 struct loader_layer_properties *prop = &instance_layers->list[i];
2328 // If this is a meta-layer, make sure it is valid
2329 if ((prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER) && !verify_meta_layer_comp_layers(inst, prop, instance_layers)) {
2330 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
2331 "Removing meta-layer %s from instance layer list since it appears invalid.", prop->info.layerName);
2333 // Delete the component layers
2334 loader_instance_heap_free(inst, prop->component_layer_names);
2336 // Remove the current invalid meta-layer from the layer list. Use memmove since we are
2337 // overlapping the source and destination addresses.
2338 memmove(&instance_layers->list[i], &instance_layers->list[i + 1],
2339 sizeof(struct loader_layer_properties) * (instance_layers->count - 1 - i));
2341 // Decrement the count (because we now have one less) and decrement the loop index since we need to
2342 // re-check this index.
2343 instance_layers->count--;
2349 // This structure is used to store the json file version
2350 // in a more manageable way.
2355 } layer_json_version;
2357 static inline bool is_valid_layer_json_version(const layer_json_version *layer_json) {
2358 // Supported versions are: 1.0.0, 1.0.1, 1.1.0, 1.1.1, and 1.1.2.
2359 if ((layer_json->major == 1 && layer_json->minor == 1 && layer_json->patch < 3) ||
2360 (layer_json->major == 1 && layer_json->minor == 0 && layer_json->patch < 2)) {
2366 static inline bool layer_json_supports_layers_tag(const layer_json_version *layer_json) {
2367 // Supported versions started in 1.0.1, so anything newer
2368 if ((layer_json->major > 1 || layer_json->minor > 0 || layer_json->patch > 1)) {
2374 static inline bool layer_json_supports_pre_instance_tag(const layer_json_version *layer_json) {
2375 // Supported versions started in 1.1.2, so anything newer
2376 return layer_json->major > 1 || layer_json->minor > 1 || (layer_json->minor == 1 && layer_json->patch > 1);
2379 static VkResult loader_read_json_layer(const struct loader_instance *inst, struct loader_layer_list *layer_instance_list,
2380 cJSON *layer_node, layer_json_version version, cJSON *item, cJSON *disable_environment,
2381 bool is_implicit, char *filename) {
2383 char *name, *type, *library_path_str, *api_version;
2384 char *implementation_version, *description;
2385 cJSON *ext_item, *library_path, *component_layers;
2386 VkExtensionProperties ext_prop;
2387 VkResult result = VK_ERROR_INITIALIZATION_FAILED;
2388 struct loader_layer_properties *props = NULL;
2391 // The following are required in the "layer" object:
2392 // (required) "name"
2393 // (required) "type"
2394 // (required) "library_path"
2395 // (required) "api_version"
2396 // (required) "implementation_version"
2397 // (required) "description"
2398 // (required for implicit layers) "disable_environment"
2399 #define GET_JSON_OBJECT(node, var) \
2401 var = cJSON_GetObjectItem(node, #var); \
2402 if (var == NULL) { \
2403 layer_node = layer_node->next; \
2404 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, \
2405 "Didn't find required layer object %s in manifest " \
2406 "JSON file, skipping this layer", \
2411 #define GET_JSON_ITEM(node, var) \
2413 item = cJSON_GetObjectItem(node, #var); \
2414 if (item == NULL) { \
2415 layer_node = layer_node->next; \
2416 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, \
2417 "Didn't find required layer value %s in manifest JSON " \
2418 "file, skipping this layer", \
2422 temp = cJSON_Print(item); \
2423 if (temp == NULL) { \
2424 layer_node = layer_node->next; \
2425 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, \
2426 "Problem accessing layer value %s in manifest JSON " \
2427 "file, skipping this layer", \
2429 result = VK_ERROR_OUT_OF_HOST_MEMORY; \
2432 temp[strlen(temp) - 1] = '\0'; \
2433 var = loader_stack_alloc(strlen(temp) + 1); \
2434 strcpy(var, &temp[1]); \
2437 GET_JSON_ITEM(layer_node, name)
2438 GET_JSON_ITEM(layer_node, type)
2439 GET_JSON_ITEM(layer_node, api_version)
2440 GET_JSON_ITEM(layer_node, implementation_version)
2441 GET_JSON_ITEM(layer_node, description)
2444 if (!strcmp(type, "DEVICE")) {
2445 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, "Device layers are deprecated skipping this layer");
2446 layer_node = layer_node->next;
2450 // Allow either GLOBAL or INSTANCE type interchangeably to handle
2451 // layers that must work with older loaders
2452 if (!strcmp(type, "INSTANCE") || !strcmp(type, "GLOBAL")) {
2453 if (layer_instance_list == NULL) {
2454 layer_node = layer_node->next;
2457 props = loader_get_next_layer_property(inst, layer_instance_list);
2458 if (NULL == props) {
2459 // Error already triggered in loader_get_next_layer_property.
2460 result = VK_ERROR_OUT_OF_HOST_MEMORY;
2463 props->type_flags = VK_LAYER_TYPE_FLAG_INSTANCE_LAYER;
2465 props->type_flags |= VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER;
2468 layer_node = layer_node->next;
2472 // Library path no longer required unless component_layers is also not defined
2473 library_path = cJSON_GetObjectItem(layer_node, "library_path");
2474 component_layers = cJSON_GetObjectItem(layer_node, "component_layers");
2475 if (NULL != library_path) {
2476 if (NULL != component_layers) {
2477 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2478 "Indicating meta-layer-specific component_layers, but also "
2479 "defining layer library path. Both are not compatible, so "
2480 "skipping this layer");
2483 props->num_component_layers = 0;
2484 props->component_layer_names = NULL;
2486 temp = cJSON_Print(library_path);
2488 layer_node = layer_node->next;
2489 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2490 "Problem accessing layer value library_path in manifest JSON "
2491 "file, skipping this layer");
2492 result = VK_ERROR_OUT_OF_HOST_MEMORY;
2495 temp[strlen(temp) - 1] = '\0';
2496 library_path_str = loader_stack_alloc(strlen(temp) + 1);
2497 strcpy(library_path_str, &temp[1]);
2500 char *fullpath = props->lib_name;
2502 if (NULL != library_path_str) {
2503 if (loader_platform_is_path(library_path_str)) {
2504 // A relative or absolute path
2505 char *name_copy = loader_stack_alloc(strlen(filename) + 1);
2506 strcpy(name_copy, filename);
2507 rel_base = loader_platform_dirname(name_copy);
2508 loader_expand_path(library_path_str, rel_base, MAX_STRING_SIZE, fullpath);
2510 // A filename which is assumed in a system directory
2511 loader_get_fullpath(library_path_str, DEFAULT_VK_LAYERS_PATH, MAX_STRING_SIZE, fullpath);
2514 } else if (NULL != component_layers) {
2515 if (version.major == 1 && (version.minor < 1 || version.patch < 1)) {
2516 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2517 "Indicating meta-layer-specific component_layers, but using older "
2518 "JSON file version.");
2520 int count = cJSON_GetArraySize(component_layers);
2521 props->num_component_layers = count;
2523 // Allocate buffer for layer names
2524 props->component_layer_names =
2525 loader_instance_heap_alloc(inst, sizeof(char[MAX_STRING_SIZE]) * count, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2526 if (NULL == props->component_layer_names) {
2527 result = VK_ERROR_OUT_OF_HOST_MEMORY;
2531 // Copy the component layers into the array
2532 for (i = 0; i < count; i++) {
2533 cJSON *comp_layer = cJSON_GetArrayItem(component_layers, i);
2534 if (NULL != comp_layer) {
2535 temp = cJSON_Print(comp_layer);
2537 result = VK_ERROR_OUT_OF_HOST_MEMORY;
2540 temp[strlen(temp) - 1] = '\0';
2541 strncpy(props->component_layer_names[i], temp + 1, MAX_STRING_SIZE - 1);
2542 props->component_layer_names[i][MAX_STRING_SIZE - 1] = '\0';
2547 // This is now, officially, a meta-layer
2548 props->type_flags |= VK_LAYER_TYPE_FLAG_META_LAYER;
2549 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "Encountered meta-layer %s", name);
2551 // Make sure we set up other things so we head down the correct branches below
2552 library_path_str = NULL;
2554 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2555 "Layer missing both library_path and component_layers fields. One or the "
2556 "other MUST be defined. Skipping this layer");
2561 GET_JSON_OBJECT(layer_node, disable_environment)
2563 #undef GET_JSON_ITEM
2564 #undef GET_JSON_OBJECT
2566 strncpy(props->info.layerName, name, sizeof(props->info.layerName));
2567 props->info.layerName[sizeof(props->info.layerName) - 1] = '\0';
2568 props->info.specVersion = loader_make_version(api_version);
2569 props->info.implementationVersion = atoi(implementation_version);
2570 strncpy((char *)props->info.description, description, sizeof(props->info.description));
2571 props->info.description[sizeof(props->info.description) - 1] = '\0';
2573 if (!disable_environment || !disable_environment->child) {
2574 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2575 "Didn't find required layer child value disable_environment"
2576 "in manifest JSON file, skipping this layer");
2577 layer_node = layer_node->next;
2580 strncpy(props->disable_env_var.name, disable_environment->child->string, sizeof(props->disable_env_var.name));
2581 props->disable_env_var.name[sizeof(props->disable_env_var.name) - 1] = '\0';
2582 strncpy(props->disable_env_var.value, disable_environment->child->valuestring, sizeof(props->disable_env_var.value));
2583 props->disable_env_var.value[sizeof(props->disable_env_var.value) - 1] = '\0';
2586 // Now get all optional items and objects and put in list:
2588 // instance_extensions
2589 // device_extensions
2590 // enable_environment (implicit layers only)
2591 #define GET_JSON_OBJECT(node, var) \
2592 { var = cJSON_GetObjectItem(node, #var); }
2593 #define GET_JSON_ITEM(node, var) \
2595 item = cJSON_GetObjectItem(node, #var); \
2596 if (item != NULL) { \
2597 temp = cJSON_Print(item); \
2598 if (temp != NULL) { \
2599 temp[strlen(temp) - 1] = '\0'; \
2600 var = loader_stack_alloc(strlen(temp) + 1); \
2601 strcpy(var, &temp[1]); \
2604 result = VK_ERROR_OUT_OF_HOST_MEMORY; \
2610 cJSON *instance_extensions, *device_extensions, *functions, *enable_environment;
2611 cJSON *entrypoints = NULL;
2612 char *vkGetInstanceProcAddr = NULL;
2613 char *vkGetDeviceProcAddr = NULL;
2614 char *vkNegotiateLoaderLayerInterfaceVersion = NULL;
2615 char *spec_version = NULL;
2616 char **entry_array = NULL;
2618 // Layer interface functions
2619 // vkGetInstanceProcAddr
2620 // vkGetDeviceProcAddr
2621 // vkNegotiateLoaderLayerInterfaceVersion (starting with JSON file 1.1.0)
2622 GET_JSON_OBJECT(layer_node, functions)
2623 if (functions != NULL) {
2624 if (version.major > 1 || version.minor >= 1) {
2625 GET_JSON_ITEM(functions, vkNegotiateLoaderLayerInterfaceVersion)
2626 if (vkNegotiateLoaderLayerInterfaceVersion != NULL)
2627 strncpy(props->functions.str_negotiate_interface, vkNegotiateLoaderLayerInterfaceVersion,
2628 sizeof(props->functions.str_negotiate_interface));
2629 props->functions.str_negotiate_interface[sizeof(props->functions.str_negotiate_interface) - 1] = '\0';
2631 props->functions.str_negotiate_interface[0] = '\0';
2633 GET_JSON_ITEM(functions, vkGetInstanceProcAddr)
2634 GET_JSON_ITEM(functions, vkGetDeviceProcAddr)
2635 if (vkGetInstanceProcAddr != NULL) {
2636 strncpy(props->functions.str_gipa, vkGetInstanceProcAddr, sizeof(props->functions.str_gipa));
2637 if (version.major > 1 || version.minor >= 1) {
2638 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2639 "Indicating layer-specific vkGetInstanceProcAddr "
2640 "function is deprecated starting with JSON file "
2641 "version 1.1.0. Instead, use the new "
2642 "vkNegotiateLayerInterfaceVersion function to "
2643 "return the GetInstanceProcAddr function for this"
2647 props->functions.str_gipa[sizeof(props->functions.str_gipa) - 1] = '\0';
2648 if (vkGetDeviceProcAddr != NULL) {
2649 strncpy(props->functions.str_gdpa, vkGetDeviceProcAddr, sizeof(props->functions.str_gdpa));
2650 if (version.major > 1 || version.minor >= 1) {
2651 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2652 "Indicating layer-specific vkGetDeviceProcAddr "
2653 "function is deprecated starting with JSON file "
2654 "version 1.1.0. Instead, use the new "
2655 "vkNegotiateLayerInterfaceVersion function to "
2656 "return the GetDeviceProcAddr function for this"
2660 props->functions.str_gdpa[sizeof(props->functions.str_gdpa) - 1] = '\0';
2663 // instance_extensions
2668 GET_JSON_OBJECT(layer_node, instance_extensions)
2669 if (instance_extensions != NULL) {
2670 int count = cJSON_GetArraySize(instance_extensions);
2671 for (i = 0; i < count; i++) {
2672 ext_item = cJSON_GetArrayItem(instance_extensions, i);
2673 GET_JSON_ITEM(ext_item, name)
2675 strncpy(ext_prop.extensionName, name, sizeof(ext_prop.extensionName));
2676 ext_prop.extensionName[sizeof(ext_prop.extensionName) - 1] = '\0';
2678 GET_JSON_ITEM(ext_item, spec_version)
2679 if (NULL != spec_version) {
2680 ext_prop.specVersion = atoi(spec_version);
2682 ext_prop.specVersion = 0;
2684 bool ext_unsupported = wsi_unsupported_instance_extension(&ext_prop);
2685 if (!ext_unsupported) {
2686 loader_add_to_ext_list(inst, &props->instance_extension_list, 1, &ext_prop);
2691 // device_extensions
2697 GET_JSON_OBJECT(layer_node, device_extensions)
2698 if (device_extensions != NULL) {
2699 int count = cJSON_GetArraySize(device_extensions);
2700 for (i = 0; i < count; i++) {
2701 ext_item = cJSON_GetArrayItem(device_extensions, i);
2702 GET_JSON_ITEM(ext_item, name)
2703 GET_JSON_ITEM(ext_item, spec_version)
2705 strncpy(ext_prop.extensionName, name, sizeof(ext_prop.extensionName));
2706 ext_prop.extensionName[sizeof(ext_prop.extensionName) - 1] = '\0';
2708 if (NULL != spec_version) {
2709 ext_prop.specVersion = atoi(spec_version);
2711 ext_prop.specVersion = 0;
2713 // entrypoints = cJSON_GetObjectItem(ext_item, "entrypoints");
2714 GET_JSON_OBJECT(ext_item, entrypoints)
2716 if (entrypoints == NULL) {
2717 loader_add_to_dev_ext_list(inst, &props->device_extension_list, &ext_prop, 0, NULL);
2720 entry_count = cJSON_GetArraySize(entrypoints);
2722 entry_array = (char **)loader_stack_alloc(sizeof(char *) * entry_count);
2724 for (j = 0; j < entry_count; j++) {
2725 ext_item = cJSON_GetArrayItem(entrypoints, j);
2726 if (ext_item != NULL) {
2727 temp = cJSON_Print(ext_item);
2729 entry_array[j] = NULL;
2730 result = VK_ERROR_OUT_OF_HOST_MEMORY;
2733 temp[strlen(temp) - 1] = '\0';
2734 entry_array[j] = loader_stack_alloc(strlen(temp) + 1);
2735 strcpy(entry_array[j], &temp[1]);
2739 loader_add_to_dev_ext_list(inst, &props->device_extension_list, &ext_prop, entry_count, entry_array);
2743 GET_JSON_OBJECT(layer_node, enable_environment)
2745 // enable_environment is optional
2746 if (enable_environment) {
2747 strncpy(props->enable_env_var.name, enable_environment->child->string, sizeof(props->enable_env_var.name));
2748 props->enable_env_var.name[sizeof(props->enable_env_var.name) - 1] = '\0';
2749 strncpy(props->enable_env_var.value, enable_environment->child->valuestring, sizeof(props->enable_env_var.value));
2750 props->enable_env_var.value[sizeof(props->enable_env_var.value) - 1] = '\0';
2754 // Read in the pre-instance stuff
2755 cJSON *pre_instance = cJSON_GetObjectItem(layer_node, "pre_instance_functions");
2757 if (!layer_json_supports_pre_instance_tag(&version)) {
2758 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2759 "Found pre_instance_functions section in layer from \"%s\". "
2760 "This section is only valid in manifest version 1.1.2 or later. The section will be ignored",
2762 } else if (!is_implicit) {
2763 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2764 "Found pre_instance_functions section in explicit layer from "
2765 "\"%s\". This section is only valid in implicit layers. The section will be ignored",
2768 cJSON *inst_ext_json = cJSON_GetObjectItem(pre_instance, "vkEnumerateInstanceExtensionProperties");
2769 if (inst_ext_json) {
2770 char *inst_ext_name = cJSON_Print(inst_ext_json);
2771 size_t len = strlen(inst_ext_name) >= MAX_STRING_SIZE ? MAX_STRING_SIZE - 3 : strlen(inst_ext_name) - 2;
2772 strncpy(props->pre_instance_functions.enumerate_instance_extension_properties, inst_ext_name + 1, len);
2773 props->pre_instance_functions.enumerate_instance_extension_properties[len] = '\0';
2774 cJSON_Free(inst_ext_name);
2777 cJSON *inst_layer_json = cJSON_GetObjectItem(pre_instance, "vkEnumerateInstanceLayerProperties");
2778 if (inst_layer_json) {
2779 char *inst_layer_name = cJSON_Print(inst_layer_json);
2780 size_t len = strlen(inst_layer_name) >= MAX_STRING_SIZE ? MAX_STRING_SIZE - 3 : strlen(inst_layer_name) - 2;
2781 strncpy(props->pre_instance_functions.enumerate_instance_layer_properties, inst_layer_name + 1, len);
2782 props->pre_instance_functions.enumerate_instance_layer_properties[len] = '\0';
2783 cJSON_Free(inst_layer_name);
2788 result = VK_SUCCESS;
2792 #undef GET_JSON_ITEM
2793 #undef GET_JSON_OBJECT
2795 if (VK_SUCCESS != result && NULL != props) {
2796 props->num_component_layers = 0;
2797 if (NULL != props->component_layer_names) {
2798 loader_instance_heap_free(inst, props->component_layer_names);
2800 props->component_layer_names = NULL;
2806 // Given a cJSON struct (json) of the top level JSON object from layer manifest
2807 // file, add entry to the layer_list. Fill out the layer_properties in this list
2808 // entry from the input cJSON object.
2812 // layer_list has a new entry and initialized accordingly.
2813 // If the json input object does not have all the required fields no entry
2814 // is added to the list.
2815 static VkResult loader_add_layer_properties(const struct loader_instance *inst, struct loader_layer_list *layer_instance_list,
2816 cJSON *json, bool is_implicit, char *filename) {
2817 // The following Fields in layer manifest file that are required:
2818 // - "file_format_version"
2819 // - If more than one "layer" object are used, then the "layers" array is
2821 VkResult result = VK_ERROR_INITIALIZATION_FAILED;
2822 cJSON *item, *layers_node, *layer_node;
2823 layer_json_version json_version = {0, 0, 0};
2825 cJSON *disable_environment = NULL;
2826 item = cJSON_GetObjectItem(json, "file_format_version");
2830 char *file_vers = cJSON_PrintUnformatted(item);
2831 if (NULL == file_vers) {
2834 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "Found manifest file %s, version %s", filename, file_vers);
2835 // Get the major/minor/and patch as integers for easier comparison
2836 vers_tok = strtok(file_vers, ".\"\n\r");
2837 if (NULL != vers_tok) {
2838 json_version.major = (uint16_t)atoi(vers_tok);
2839 vers_tok = strtok(NULL, ".\"\n\r");
2840 if (NULL != vers_tok) {
2841 json_version.minor = (uint16_t)atoi(vers_tok);
2842 vers_tok = strtok(NULL, ".\"\n\r");
2843 if (NULL != vers_tok) {
2844 json_version.patch = (uint16_t)atoi(vers_tok);
2849 if (!is_valid_layer_json_version(&json_version)) {
2850 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2851 "loader_add_layer_properties: %s invalid layer "
2852 "manifest file version %d.%d.%d. May cause errors.",
2853 filename, json_version.major, json_version.minor, json_version.patch);
2855 cJSON_Free(file_vers);
2857 // If "layers" is present, read in the array of layer objects
2858 layers_node = cJSON_GetObjectItem(json, "layers");
2859 if (layers_node != NULL) {
2860 int numItems = cJSON_GetArraySize(layers_node);
2861 if (!layer_json_supports_layers_tag(&json_version)) {
2862 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2863 "loader_add_layer_properties: \'layers\' tag not "
2864 "supported until file version 1.0.1, but %s is "
2865 "reporting version %s",
2866 filename, file_vers);
2868 for (int curLayer = 0; curLayer < numItems; curLayer++) {
2869 layer_node = cJSON_GetArrayItem(layers_node, curLayer);
2870 if (layer_node == NULL) {
2871 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2872 "loader_add_layer_properties: Can not find "
2873 "\'layers\' array element %d object in manifest "
2874 "JSON file %s. Skipping this file",
2875 curLayer, filename);
2878 result = loader_read_json_layer(inst, layer_instance_list, layer_node, json_version, item, disable_environment,
2879 is_implicit, filename);
2882 // Otherwise, try to read in individual layers
2883 layer_node = cJSON_GetObjectItem(json, "layer");
2884 if (layer_node == NULL) {
2885 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2886 "loader_add_layer_properties: Can not find \'layer\' "
2887 "object in manifest JSON file %s. Skipping this file.",
2891 // Loop through all "layer" objects in the file to get a count of them
2893 uint16_t layer_count = 0;
2894 cJSON *tempNode = layer_node;
2896 tempNode = tempNode->next;
2898 } while (tempNode != NULL);
2900 // Throw a warning if we encounter multiple "layer" objects in file
2901 // versions newer than 1.0.0. Having multiple objects with the same
2902 // name at the same level is actually a JSON standard violation.
2903 if (layer_count > 1 && layer_json_supports_layers_tag(&json_version)) {
2904 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2905 "loader_add_layer_properties: Multiple \'layer\' nodes"
2906 " are deprecated starting in file version \"1.0.1\". "
2907 "Please use \'layers\' : [] array instead in %s.",
2911 result = loader_read_json_layer(inst, layer_instance_list, layer_node, json_version, item, disable_environment,
2912 is_implicit, filename);
2913 layer_node = layer_node->next;
2914 } while (layer_node != NULL);
2923 // Find the Vulkan library manifest files.
2925 // This function scans the "location" or "env_override" directories/files
2926 // for a list of JSON manifest files. If env_override is non-NULL
2927 // and has a valid value. Then the location is ignored. Otherwise
2928 // location is used to look for manifest files. The location
2929 // is interpreted as Registry path on Windows and a directory path(s)
2930 // on Linux. "home_location" is an additional directory in the users home
2931 // directory to look at. It is expanded into the dir path
2932 // $XDG_DATA_HOME/home_location or $HOME/.local/share/home_location depending
2933 // on environment variables. This "home_location" is only used on Linux.
2937 // A string list of manifest files to be opened in out_files param.
2938 // List has a pointer to string for each manifest filename.
2939 // When done using the list in out_files, pointers should be freed.
2940 // Location or override string lists can be either files or directories as
2942 // | location | override
2943 // --------------------------------
2944 // Win ICD | files | files
2945 // Win Layer | files | dirs
2946 // Linux ICD | dirs | files
2947 // Linux Layer| dirs | dirs
2948 static VkResult loader_get_manifest_files(const struct loader_instance *inst, const char *env_override, const char *source_override,
2949 bool is_layer, bool warn_if_not_present, const char *location,
2950 const char *relative_location, struct loader_manifest_files *out_files) {
2951 const char *override = NULL;
2952 char *override_getenv = NULL;
2953 char *loc, *orig_loc = NULL;
2955 char *file, *next_file, *name;
2956 size_t alloced_count = 64;
2957 char full_path[2048];
2959 bool list_is_dirs = false;
2960 struct dirent *dent;
2961 VkResult res = VK_SUCCESS;
2963 out_files->count = 0;
2964 out_files->filename_list = NULL;
2966 if (source_override != NULL) {
2967 override = source_override;
2968 } else if (env_override != NULL) {
2969 #if !defined(_WIN32)
2970 if (geteuid() != getuid() || getegid() != getgid()) {
2971 // Don't allow setuid apps to use the env var:
2972 env_override = NULL;
2975 if (env_override != NULL) {
2976 override = override_getenv = loader_secure_getenv(env_override, inst);
2980 #if !defined(_WIN32)
2981 if (relative_location == NULL) {
2983 relative_location = NULL;
2984 if (location == NULL) {
2986 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2987 "loader_get_manifest_files: Can not get manifest files with "
2988 "NULL location, env_override=%s",
2989 (env_override != NULL) ? env_override : "");
2990 res = VK_ERROR_INITIALIZATION_FAILED;
2995 list_is_dirs = (is_layer && override != NULL) ? true : false;
2997 list_is_dirs = (override == NULL || is_layer) ? true : false;
2999 // Make a copy of the input we are using so it is not modified
3000 // Also handle getting the location(s) from registry on Windows
3001 if (override == NULL) {
3002 size_t loc_size = 0;
3003 #if !defined(_WIN32)
3004 const char *xdgconfdirs = loader_secure_getenv("XDG_CONFIG_DIRS", inst);
3005 const char *xdgdatadirs = loader_secure_getenv("XDG_DATA_DIRS", inst);
3006 if (xdgconfdirs == NULL || xdgconfdirs[0] == '\0') xdgconfdirs = FALLBACK_CONFIG_DIRS;
3007 if (xdgdatadirs == NULL || xdgdatadirs[0] == '\0') xdgdatadirs = FALLBACK_DATA_DIRS;
3008 const size_t rel_size = strlen(relative_location);
3009 // Leave space for trailing separators
3010 loc_size += strlen(xdgconfdirs) + strlen(xdgdatadirs) + 2 * rel_size + 2;
3011 for (const char *x = xdgconfdirs; *x; ++x)
3012 if (*x == PATH_SEPARATOR) loc_size += rel_size;
3013 for (const char *x = xdgdatadirs; *x; ++x)
3014 if (*x == PATH_SEPARATOR) loc_size += rel_size;
3015 loc_size += strlen(SYSCONFDIR) + rel_size + 1;
3016 #if defined(EXTRASYSCONFDIR)
3017 loc_size += strlen(EXTRASYSCONFDIR) + rel_size + 1;
3020 loc_size += strlen(location) + 1;
3022 loc = loader_stack_alloc(loc_size);
3024 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3025 "loader_get_manifest_files: Failed to allocate "
3026 "%d bytes for manifest file location.",
3028 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3031 char *loc_write = loc;
3032 #if !defined(_WIN32)
3033 const char *loc_read;
3036 loc_read = &xdgconfdirs[0];
3038 while (loc_read[start] != '\0') {
3039 while (loc_read[start] == PATH_SEPARATOR) {
3043 while (loc_read[stop] != PATH_SEPARATOR && loc_read[stop] != '\0') {
3046 const size_t s = stop - start;
3048 memcpy(loc_write, &loc_read[start], s);
3050 memcpy(loc_write, relative_location, rel_size);
3051 loc_write += rel_size;
3052 *loc_write++ = PATH_SEPARATOR;
3057 memcpy(loc_write, SYSCONFDIR, strlen(SYSCONFDIR));
3058 loc_write += strlen(SYSCONFDIR);
3059 memcpy(loc_write, relative_location, rel_size);
3060 loc_write += rel_size;
3061 *loc_write++ = PATH_SEPARATOR;
3063 #if defined(EXTRASYSCONFDIR)
3064 memcpy(loc_write, EXTRASYSCONFDIR, strlen(EXTRASYSCONFDIR));
3065 loc_write += strlen(EXTRASYSCONFDIR);
3066 memcpy(loc_write, relative_location, rel_size);
3067 loc_write += rel_size;
3068 *loc_write++ = PATH_SEPARATOR;
3071 loc_read = &xdgdatadirs[0];
3073 while (loc_read[start] != '\0') {
3074 while (loc_read[start] == PATH_SEPARATOR) {
3078 while (loc_read[stop] != PATH_SEPARATOR && loc_read[stop] != '\0') {
3081 const size_t s = stop - start;
3083 memcpy(loc_write, &loc_read[start], s);
3085 memcpy(loc_write, relative_location, rel_size);
3086 loc_write += rel_size;
3087 *loc_write++ = PATH_SEPARATOR;
3094 memcpy(loc_write, location, strlen(location));
3095 loc_write += strlen(location);
3097 assert(loc_write - loc < (ptrdiff_t)loc_size);
3101 VkResult regHKR_result = VK_SUCCESS;
3103 DWORD reg_size = 4096;
3105 // These calls look at the PNP/Device section of the registry.
3106 if (!strncmp(loc, DEFAULT_VK_DRIVERS_INFO, sizeof(DEFAULT_VK_DRIVERS_INFO))) {
3107 regHKR_result = loaderGetDeviceRegistryFiles(inst, ®, ®_size, LoaderPnpDriverRegistry());
3108 } else if (!strncmp(loc, DEFAULT_VK_ELAYERS_INFO, sizeof(DEFAULT_VK_ELAYERS_INFO))) {
3109 regHKR_result = loaderGetDeviceRegistryFiles(inst, ®, ®_size, LoaderPnpELayerRegistry());
3110 } else if (!strncmp(loc, DEFAULT_VK_ILAYERS_INFO, sizeof(DEFAULT_VK_ILAYERS_INFO))) {
3111 regHKR_result = loaderGetDeviceRegistryFiles(inst, ®, ®_size, LoaderPnpILayerRegistry());
3114 // This call looks into the Khronos non-device specific section of the registry.
3115 VkResult reg_result = loaderGetRegistryFiles(inst, loc, is_layer, ®, ®_size);
3117 if ((VK_SUCCESS != reg_result && VK_SUCCESS != regHKR_result) || NULL == reg) {
3119 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3120 "loader_get_manifest_files: Registry lookup failed "
3121 "to get ICD manifest files. Possibly missing Vulkan"
3123 if (VK_SUCCESS == regHKR_result || VK_ERROR_OUT_OF_HOST_MEMORY == regHKR_result) {
3124 res = regHKR_result;
3125 } else if (VK_SUCCESS == reg_result || VK_ERROR_OUT_OF_HOST_MEMORY == reg_result) {
3128 res = VK_ERROR_INCOMPATIBLE_DRIVER;
3131 if (warn_if_not_present) {
3132 // This is only a warning for layers
3133 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3134 "loader_get_manifest_files: Registry lookup failed "
3135 "to get layer manifest files.");
3137 if (reg_result == VK_ERROR_OUT_OF_HOST_MEMORY) {
3140 // Return success for now since it's not critical for layers
3150 loc = loader_stack_alloc(strlen(override) + 1);
3152 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3153 "loader_get_manifest_files: Failed to allocate space for "
3154 "override environment variable of length %d",
3155 strlen(override) + 1);
3156 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3159 strcpy(loc, override);
3162 // Print out the paths being searched if debugging is enabled
3163 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Searching the following paths for manifest files: %s\n", loc);
3167 next_file = loader_get_next_path(file);
3169 sysdir = opendir(file);
3172 dent = readdir(sysdir);
3173 if (dent == NULL) break;
3174 name = &(dent->d_name[0]);
3175 loader_get_fullpath(name, file, sizeof(full_path), full_path);
3182 // only Linux has relative paths
3184 // make a copy of location so it isn't modified
3185 dir = loader_stack_alloc(strlen(loc) + 1);
3187 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3188 "loader_get_manifest_files: Failed to allocate "
3189 "space for relative location path length %d",
3195 loader_get_fullpath(file, dir, sizeof(full_path), full_path);
3201 // Look for files ending with ".json" suffix
3202 uint32_t nlen = (uint32_t)strlen(name);
3203 const char *suf = name + nlen - 5;
3205 // Check if the file is already present
3206 bool file_already_loaded = false;
3207 for (uint32_t i = 0; i < out_files->count; ++i) {
3208 if (!strcmp(out_files->filename_list[i], name)) {
3209 file_already_loaded = true;
3213 if (!file_already_loaded && (nlen > 5) && !strncmp(suf, ".json", 5)) {
3214 if (out_files->count == 0) {
3215 out_files->filename_list =
3216 loader_instance_heap_alloc(inst, alloced_count * sizeof(char *), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
3217 if (NULL == out_files->filename_list) {
3218 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3219 "loader_get_manifest_files: Failed to allocate space for manifest file name list");
3220 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3223 } else if (out_files->count == alloced_count) {
3225 loader_instance_heap_realloc(inst, out_files->filename_list, alloced_count * sizeof(char *),
3226 alloced_count * sizeof(char *) * 2, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
3227 if (NULL == new_ptr) {
3228 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3229 "loader_get_manifest_files: Failed to reallocate space for manifest file name list");
3230 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3233 out_files->filename_list = new_ptr;
3236 out_files->filename_list[out_files->count] =
3237 loader_instance_heap_alloc(inst, strlen(name) + 1, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
3238 if (out_files->filename_list[out_files->count] == NULL) {
3239 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3240 "loader_get_manifest_files: Failed to allocate "
3241 "space for manifest file %d list",
3243 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3246 strcpy(out_files->filename_list[out_files->count], name);
3248 } else if(file_already_loaded) {
3249 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3250 "Skipping manifest file %s - The file has already been read once", name);
3251 } else if (!list_is_dirs) {
3252 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, "Skipping manifest file %s, file name must end in .json",
3256 dent = readdir(sysdir);
3260 name = &(dent->d_name[0]);
3261 loader_get_fullpath(name, file, sizeof(full_path), full_path);
3272 #if !defined(_WIN32)
3273 if (relative_location != NULL && (next_file == NULL || *next_file == '\0') && override == NULL) {
3274 char *xdgdatahome = loader_secure_getenv("XDG_DATA_HOME", inst);
3276 if (xdgdatahome != NULL) {
3277 size_t alloc_len = strlen(xdgdatahome) + 2 + strlen(relative_location);
3278 char *home_loc = loader_stack_alloc(alloc_len);
3279 if (home_loc == NULL) {
3280 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3281 "loader_get_manifest_files: Failed to allocate "
3282 "space for manifest file XDG Home location");
3283 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3286 strcpy(home_loc, xdgdatahome);
3287 // Add directory separator if needed
3288 if (relative_location[0] != DIRECTORY_SYMBOL) {
3289 len = strlen(home_loc);
3290 home_loc[len] = DIRECTORY_SYMBOL;
3291 home_loc[len + 1] = '\0';
3293 strncat(home_loc, relative_location, alloc_len);
3295 next_file = loader_get_next_path(file);
3296 relative_location = NULL;
3298 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Searching the following path for manifest files: %s\n",
3300 list_is_dirs = true;
3303 char *home = loader_secure_getenv("HOME", inst);
3305 size_t alloc_len = strlen(home) + 16 + strlen(relative_location);
3306 char *home_loc = loader_stack_alloc(alloc_len);
3307 if (home_loc == NULL) {
3308 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3309 "loader_get_manifest_files: Failed to allocate "
3310 "space for manifest file Home location");
3311 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3314 strncpy(home_loc, home, alloc_len);
3317 if (home[len] != DIRECTORY_SYMBOL) {
3318 home_loc[len] = DIRECTORY_SYMBOL;
3319 home_loc[len + 1] = '\0';
3321 strncat(home_loc, ".local/share", alloc_len);
3323 if (relative_location[0] != DIRECTORY_SYMBOL) {
3324 len = strlen(home_loc);
3325 home_loc[len] = DIRECTORY_SYMBOL;
3326 home_loc[len + 1] = '\0';
3328 strncat(home_loc, relative_location, alloc_len);
3330 next_file = loader_get_next_path(file);
3331 relative_location = NULL;
3333 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Searching the following path for manifest files: %s\n",
3335 list_is_dirs = true;
3337 // without knowing HOME, we just.. give up
3345 if (VK_SUCCESS != res && NULL != out_files->filename_list) {
3346 for (uint32_t remove = 0; remove < out_files->count; remove++) {
3347 loader_instance_heap_free(inst, out_files->filename_list[remove]);
3349 loader_instance_heap_free(inst, out_files->filename_list);
3350 out_files->count = 0;
3351 out_files->filename_list = NULL;
3354 if (NULL != sysdir) {
3358 if (override_getenv != NULL) {
3359 loader_free_getenv(override_getenv, inst);
3362 if (NULL != reg && reg != orig_loc) {
3363 loader_instance_heap_free(inst, reg);
3368 void loader_init_icd_lib_list() {}
3370 void loader_destroy_icd_lib_list() {}
3372 // Try to find the Vulkan ICD driver(s).
3374 // This function scans the default system loader path(s) or path
3375 // specified by the \c VK_ICD_FILENAMES environment variable in
3376 // order to find loadable VK ICDs manifest files. From these
3377 // manifest files it finds the ICD libraries.
3381 // (on result == VK_SUCCESS) a list of icds that were discovered
3382 VkResult loader_icd_scan(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list) {
3384 uint16_t file_major_vers = 0;
3385 uint16_t file_minor_vers = 0;
3386 uint16_t file_patch_vers = 0;
3388 struct loader_manifest_files manifest_files;
3389 VkResult res = VK_SUCCESS;
3390 bool lockedMutex = false;
3392 uint32_t num_good_icds = 0;
3394 memset(&manifest_files, 0, sizeof(struct loader_manifest_files));
3396 res = loader_scanned_icd_init(inst, icd_tramp_list);
3397 if (VK_SUCCESS != res) {
3401 // Get a list of manifest files for ICDs
3402 res = loader_get_manifest_files(inst, "VK_ICD_FILENAMES", NULL, false, true, DEFAULT_VK_DRIVERS_INFO, RELATIVE_VK_DRIVERS_INFO,
3404 if (VK_SUCCESS != res || manifest_files.count == 0) {
3408 loader_platform_thread_lock_mutex(&loader_json_lock);
3410 for (uint32_t i = 0; i < manifest_files.count; i++) {
3411 file_str = manifest_files.filename_list[i];
3412 if (file_str == NULL) {
3416 VkResult temp_res = loader_get_json(inst, file_str, &json);
3417 if (NULL == json || temp_res != VK_SUCCESS) {
3422 // If we haven't already found an ICD, copy this result to
3423 // the returned result.
3424 if (num_good_icds == 0) {
3427 if (temp_res == VK_ERROR_OUT_OF_HOST_MEMORY) {
3435 cJSON *item, *itemICD;
3436 item = cJSON_GetObjectItem(json, "file_format_version");
3438 if (num_good_icds == 0) {
3439 res = VK_ERROR_INITIALIZATION_FAILED;
3441 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3442 "loader_icd_scan: ICD JSON %s does not have a"
3443 " \'file_format_version\' field. Skipping ICD JSON.",
3450 char *file_vers = cJSON_Print(item);
3451 if (NULL == file_vers) {
3452 // Only reason the print can fail is if there was an allocation issue
3453 if (num_good_icds == 0) {
3454 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3456 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3457 "loader_icd_scan: Failed retrieving ICD JSON %s"
3458 " \'file_format_version\' field. Skipping ICD JSON",
3464 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "Found ICD manifest file %s, version %s", file_str, file_vers);
3466 // Get the major/minor/and patch as integers for easier comparison
3467 vers_tok = strtok(file_vers, ".\"\n\r");
3468 if (NULL != vers_tok) {
3469 file_major_vers = (uint16_t)atoi(vers_tok);
3470 vers_tok = strtok(NULL, ".\"\n\r");
3471 if (NULL != vers_tok) {
3472 file_minor_vers = (uint16_t)atoi(vers_tok);
3473 vers_tok = strtok(NULL, ".\"\n\r");
3474 if (NULL != vers_tok) {
3475 file_patch_vers = (uint16_t)atoi(vers_tok);
3480 if (file_major_vers != 1 || file_minor_vers != 0 || file_patch_vers > 1) {
3481 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3482 "loader_icd_scan: Unexpected manifest file version "
3483 "(expected 1.0.0 or 1.0.1), may cause errors");
3485 cJSON_Free(file_vers);
3487 itemICD = cJSON_GetObjectItem(json, "ICD");
3488 if (itemICD != NULL) {
3489 item = cJSON_GetObjectItem(itemICD, "library_path");
3491 char *temp = cJSON_Print(item);
3492 if (!temp || strlen(temp) == 0) {
3493 if (num_good_icds == 0) {
3494 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3496 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3497 "loader_icd_scan: Failed retrieving ICD JSON %s"
3498 " \'library_path\' field. Skipping ICD JSON.",
3505 // strip out extra quotes
3506 temp[strlen(temp) - 1] = '\0';
3507 char *library_path = loader_stack_alloc(strlen(temp) + 1);
3508 if (NULL == library_path) {
3509 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3510 "loader_icd_scan: Failed to allocate space for "
3511 "ICD JSON %s \'library_path\' value. Skipping "
3514 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3520 strcpy(library_path, &temp[1]);
3522 if (strlen(library_path) == 0) {
3523 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3524 "loader_icd_scan: ICD JSON %s \'library_path\'"
3525 " field is empty. Skipping ICD JSON.",
3531 char fullpath[MAX_STRING_SIZE];
3532 // Print out the paths being searched if debugging is enabled
3533 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Searching for ICD drivers named %s, using default dir %s",
3534 library_path, DEFAULT_VK_DRIVERS_PATH);
3535 if (loader_platform_is_path(library_path)) {
3536 // a relative or absolute path
3537 char *name_copy = loader_stack_alloc(strlen(file_str) + 1);
3539 strcpy(name_copy, file_str);
3540 rel_base = loader_platform_dirname(name_copy);
3541 loader_expand_path(library_path, rel_base, sizeof(fullpath), fullpath);
3543 // a filename which is assumed in a system directory
3544 loader_get_fullpath(library_path, DEFAULT_VK_DRIVERS_PATH, sizeof(fullpath), fullpath);
3548 item = cJSON_GetObjectItem(itemICD, "api_version");
3550 temp = cJSON_Print(item);
3552 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3553 "loader_icd_scan: Failed retrieving ICD JSON %s"
3554 " \'api_version\' field. Skipping ICD JSON.",
3557 // Only reason the print can fail is if there was an
3559 if (num_good_icds == 0) {
3560 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3568 vers = loader_make_version(temp);
3571 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3572 "loader_icd_scan: ICD JSON %s does not have an"
3573 " \'api_version\' field.",
3577 res = loader_scanned_icd_add(inst, icd_tramp_list, fullpath, vers);
3578 if (VK_SUCCESS != res) {
3579 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3580 "loader_icd_scan: Failed to add ICD JSON %s. "
3581 " Skipping ICD JSON.",
3589 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3590 "loader_icd_scan: Failed to find \'library_path\' "
3591 "object in ICD JSON file %s. Skipping ICD JSON.",
3595 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3596 "loader_icd_scan: Can not find \'ICD\' object in ICD JSON "
3597 "file %s. Skipping ICD JSON",
3611 if (NULL != manifest_files.filename_list) {
3612 for (uint32_t i = 0; i < manifest_files.count; i++) {
3613 if (NULL != manifest_files.filename_list[i]) {
3614 loader_instance_heap_free(inst, manifest_files.filename_list[i]);
3617 loader_instance_heap_free(inst, manifest_files.filename_list);
3620 loader_platform_thread_unlock_mutex(&loader_json_lock);
3626 void loader_layer_scan(const struct loader_instance *inst, struct loader_layer_list *instance_layers) {
3628 struct loader_manifest_files manifest_files[2]; // [0] = explicit, [1] = implicit
3631 bool lockedMutex = false;
3633 memset(manifest_files, 0, sizeof(struct loader_manifest_files) * 2);
3635 // Get a list of manifest files for explicit layers
3636 if (VK_SUCCESS != loader_get_manifest_files(inst, LAYERS_PATH_ENV, LAYERS_SOURCE_PATH, true, true, DEFAULT_VK_ELAYERS_INFO,
3637 RELATIVE_VK_ELAYERS_INFO, &manifest_files[0])) {
3641 // Get a list of manifest files for any implicit layers
3642 // Pass NULL for environment variable override - implicit layers are not
3643 // overridden by LAYERS_PATH_ENV
3644 if (VK_SUCCESS != loader_get_manifest_files(inst, NULL, NULL, true, false, DEFAULT_VK_ILAYERS_INFO, RELATIVE_VK_ILAYERS_INFO,
3645 &manifest_files[1])) {
3649 // Make sure we have at least one layer, if not, go ahead and return
3650 if (manifest_files[0].count == 0 && manifest_files[1].count == 0) {
3654 // cleanup any previously scanned libraries
3655 loader_delete_layer_properties(inst, instance_layers);
3657 loader_platform_thread_lock_mutex(&loader_json_lock);
3659 for (implicit = 0; implicit < 2; implicit++) {
3660 for (uint32_t i = 0; i < manifest_files[implicit].count; i++) {
3661 file_str = manifest_files[implicit].filename_list[i];
3662 if (file_str == NULL) continue;
3664 // parse file into JSON struct
3665 VkResult res = loader_get_json(inst, file_str, &json);
3666 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
3668 } else if (VK_SUCCESS != res || NULL == json) {
3672 VkResult local_res = loader_add_layer_properties(inst, instance_layers, json, (implicit == 1), file_str);
3675 // If the error is anything other than out of memory we still want to try to load the other layers
3676 if (VK_ERROR_OUT_OF_HOST_MEMORY == local_res) {
3682 // See if "VK_LAYER_LUNARG_standard_validation" already in list.
3683 bool found_std_val = false;
3684 for (uint32_t i = 0; i < instance_layers->count; i++) {
3685 struct loader_layer_properties *props = &instance_layers->list[i];
3686 if (strcmp(props->info.layerName, std_validation_str) == 0) {
3687 found_std_val = true;
3692 // If we didn't find the VK_LAYER_LUNARG_standard_validation meta-layer in
3693 // the list, then we need to add it manually. This is likely because we're
3694 // dealing with a new loader, but an old layer folder.
3695 if (!found_std_val && !loader_add_legacy_std_val_layer(inst, instance_layers)) {
3699 // Verify any meta-layers in the list are valid and all the component layers are
3700 // actually present in the available layer list
3701 verify_all_meta_layers(inst, instance_layers);
3705 for (uint32_t manFile = 0; manFile < 2; manFile++) {
3706 if (NULL != manifest_files[manFile].filename_list) {
3707 for (uint32_t i = 0; i < manifest_files[manFile].count; i++) {
3708 if (NULL != manifest_files[manFile].filename_list[i]) {
3709 loader_instance_heap_free(inst, manifest_files[manFile].filename_list[i]);
3712 loader_instance_heap_free(inst, manifest_files[manFile].filename_list);
3716 loader_platform_thread_unlock_mutex(&loader_json_lock);
3720 void loader_implicit_layer_scan(const struct loader_instance *inst, struct loader_layer_list *instance_layers) {
3722 struct loader_manifest_files manifest_files;
3726 // Pass NULL for environment variable override - implicit layers are not
3727 // overridden by LAYERS_PATH_ENV
3728 VkResult res = loader_get_manifest_files(inst, NULL, NULL, true, false, DEFAULT_VK_ILAYERS_INFO, RELATIVE_VK_ILAYERS_INFO,
3730 if (VK_SUCCESS != res || manifest_files.count == 0) {
3734 // Cleanup any previously scanned libraries
3735 loader_delete_layer_properties(inst, instance_layers);
3737 loader_platform_thread_lock_mutex(&loader_json_lock);
3739 for (i = 0; i < manifest_files.count; i++) {
3740 file_str = manifest_files.filename_list[i];
3741 if (file_str == NULL) {
3745 // parse file into JSON struct
3746 res = loader_get_json(inst, file_str, &json);
3747 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
3749 } else if (VK_SUCCESS != res || NULL == json) {
3753 res = loader_add_layer_properties(inst, instance_layers, json, true, file_str);
3755 loader_instance_heap_free(inst, file_str);
3758 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
3762 loader_instance_heap_free(inst, manifest_files.filename_list);
3763 loader_platform_thread_unlock_mutex(&loader_json_lock);
3766 // Check if an implicit layer should be enabled.
3767 bool loader_is_implicit_layer_enabled(const struct loader_instance *inst, const struct loader_layer_properties *prop) {
3768 bool enable = false;
3769 char *env_value = NULL;
3771 // if no enable_environment variable is specified, this implicit layer
3772 // should always be enabled. Otherwise check if the variable is set
3773 if (prop->enable_env_var.name[0] == 0) {
3776 env_value = loader_secure_getenv(prop->enable_env_var.name, inst);
3777 if (env_value && !strcmp(prop->enable_env_var.value, env_value)) enable = true;
3778 loader_free_getenv(env_value, inst);
3781 // disable_environment has priority, i.e. if both enable and disable
3782 // environment variables are set, the layer is disabled. Implicit
3783 // layers are required to have a disable_environment variables
3784 env_value = loader_secure_getenv(prop->disable_env_var.name, inst);
3785 if (env_value && !strcmp(prop->disable_env_var.value, env_value)) enable = false;
3786 loader_free_getenv(env_value, inst);
3791 static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL loader_gpdpa_instance_internal(VkInstance inst, const char *pName) {
3792 // inst is not wrapped
3793 if (inst == VK_NULL_HANDLE) {
3796 VkLayerInstanceDispatchTable *disp_table = *(VkLayerInstanceDispatchTable **)inst;
3799 if (disp_table == NULL) return NULL;
3802 addr = loader_lookup_instance_dispatch_table(disp_table, pName, &found_name);
3807 if (loader_phys_dev_ext_gpa(loader_get_instance(inst), pName, true, NULL, &addr)) return addr;
3809 // Don't call down the chain, this would be an infinite loop
3810 loader_log(NULL, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, "loader_gpdpa_instance_internal() unrecognized name %s", pName);
3814 static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL loader_gpdpa_instance_terminator(VkInstance inst, const char *pName) {
3815 // inst is not wrapped
3816 if (inst == VK_NULL_HANDLE) {
3819 VkLayerInstanceDispatchTable *disp_table = *(VkLayerInstanceDispatchTable **)inst;
3822 if (disp_table == NULL) return NULL;
3825 addr = loader_lookup_instance_dispatch_table(disp_table, pName, &found_name);
3830 // Get the terminator, but don't perform checking since it should already
3831 // have been setup if we get here.
3832 if (loader_phys_dev_ext_gpa(loader_get_instance(inst), pName, false, NULL, &addr)) {
3836 // Don't call down the chain, this would be an infinite loop
3837 loader_log(NULL, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, "loader_gpdpa_instance_terminator() unrecognized name %s", pName);
3841 static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL loader_gpa_instance_internal(VkInstance inst, const char *pName) {
3842 if (!strcmp(pName, "vkGetInstanceProcAddr")) {
3843 return (PFN_vkVoidFunction)loader_gpa_instance_internal;
3845 if (!strcmp(pName, "vk_layerGetPhysicalDeviceProcAddr")) {
3846 return (PFN_vkVoidFunction)loader_gpdpa_instance_terminator;
3848 if (!strcmp(pName, "vkCreateInstance")) {
3849 return (PFN_vkVoidFunction)terminator_CreateInstance;
3851 if (!strcmp(pName, "vkCreateDevice")) {
3852 return (PFN_vkVoidFunction)terminator_CreateDevice;
3855 // inst is not wrapped
3856 if (inst == VK_NULL_HANDLE) {
3859 VkLayerInstanceDispatchTable *disp_table = *(VkLayerInstanceDispatchTable **)inst;
3862 if (disp_table == NULL) return NULL;
3865 addr = loader_lookup_instance_dispatch_table(disp_table, pName, &found_name);
3870 // Don't call down the chain, this would be an infinite loop
3871 loader_log(NULL, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, "loader_gpa_instance_internal() unrecognized name %s", pName);
3875 VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL loader_gpa_device_internal(VkDevice device, const char *pName) {
3876 struct loader_device *dev;
3877 struct loader_icd_term *icd_term = loader_get_icd_and_device(device, &dev, NULL);
3879 // Return this function if a layer above here is asking for the vkGetDeviceProcAddr.
3880 // This is so we can properly intercept any device commands needing a terminator.
3881 if (!strcmp(pName, "vkGetDeviceProcAddr")) {
3882 return (PFN_vkVoidFunction)loader_gpa_device_internal;
3885 // NOTE: Device Funcs needing Trampoline/Terminator.
3886 // Overrides for device functions needing a trampoline and
3887 // a terminator because certain device entry-points still need to go
3888 // through a terminator before hitting the ICD. This could be for
3889 // several reasons, but the main one is currently unwrapping an
3890 // object before passing the appropriate info along to the ICD.
3891 // This is why we also have to override the direct ICD call to
3892 // vkGetDeviceProcAddr to intercept those calls.
3893 PFN_vkVoidFunction addr = get_extension_device_proc_terminator(pName);
3898 return icd_term->dispatch.GetDeviceProcAddr(device, pName);
3901 // Initialize device_ext dispatch table entry as follows:
3902 // If dev == NULL find all logical devices created within this instance and
3903 // init the entry (given by idx) in the ext dispatch table.
3904 // If dev != NULL only initialize the entry in the given dev's dispatch table.
3905 // The initialization value is gotten by calling down the device chain with
3907 // If GDPA returns NULL then don't initialize the dispatch table entry.
3908 static void loader_init_dispatch_dev_ext_entry(struct loader_instance *inst, struct loader_device *dev, uint32_t idx,
3909 const char *funcName)
3914 gdpa_value = dev->loader_dispatch.core_dispatch.GetDeviceProcAddr(dev->chain_device, funcName);
3915 if (gdpa_value != NULL) dev->loader_dispatch.ext_dispatch.dev_ext[idx] = (PFN_vkDevExt)gdpa_value;
3917 for (struct loader_icd_term *icd_term = inst->icd_terms; icd_term != NULL; icd_term = icd_term->next) {
3918 struct loader_device *ldev = icd_term->logical_device_list;
3920 gdpa_value = ldev->loader_dispatch.core_dispatch.GetDeviceProcAddr(ldev->chain_device, funcName);
3921 if (gdpa_value != NULL) ldev->loader_dispatch.ext_dispatch.dev_ext[idx] = (PFN_vkDevExt)gdpa_value;
3928 // Find all dev extension in the hash table and initialize the dispatch table
3929 // for dev for each of those extension entrypoints found in hash table.
3930 void loader_init_dispatch_dev_ext(struct loader_instance *inst, struct loader_device *dev) {
3931 for (uint32_t i = 0; i < MAX_NUM_UNKNOWN_EXTS; i++) {
3932 if (inst->dev_ext_disp_hash[i].func_name != NULL)
3933 loader_init_dispatch_dev_ext_entry(inst, dev, i, inst->dev_ext_disp_hash[i].func_name);
3937 static bool loader_check_icds_for_dev_ext_address(struct loader_instance *inst, const char *funcName) {
3938 struct loader_icd_term *icd_term;
3939 icd_term = inst->icd_terms;
3940 while (NULL != icd_term) {
3941 if (icd_term->scanned_icd->GetInstanceProcAddr(icd_term->instance, funcName))
3942 // this icd supports funcName
3944 icd_term = icd_term->next;
3950 static bool loader_check_layer_list_for_dev_ext_address(const struct loader_layer_list *const layers, const char *funcName) {
3951 // Iterate over the layers.
3952 for (uint32_t layer = 0; layer < layers->count; ++layer) {
3953 // Iterate over the extensions.
3954 const struct loader_device_extension_list *const extensions = &(layers->list[layer].device_extension_list);
3955 for (uint32_t extension = 0; extension < extensions->count; ++extension) {
3956 // Iterate over the entry points.
3957 const struct loader_dev_ext_props *const property = &(extensions->list[extension]);
3958 for (uint32_t entry = 0; entry < property->entrypoint_count; ++entry) {
3959 if (strcmp(property->entrypoints[entry], funcName) == 0) {
3969 static void loader_free_dev_ext_table(struct loader_instance *inst) {
3970 for (uint32_t i = 0; i < MAX_NUM_UNKNOWN_EXTS; i++) {
3971 loader_instance_heap_free(inst, inst->dev_ext_disp_hash[i].func_name);
3972 loader_instance_heap_free(inst, inst->dev_ext_disp_hash[i].list.index);
3974 memset(inst->dev_ext_disp_hash, 0, sizeof(inst->dev_ext_disp_hash));
3977 static bool loader_add_dev_ext_table(struct loader_instance *inst, uint32_t *ptr_idx, const char *funcName) {
3979 uint32_t idx = *ptr_idx;
3980 struct loader_dispatch_hash_list *list = &inst->dev_ext_disp_hash[idx].list;
3982 if (!inst->dev_ext_disp_hash[idx].func_name) {
3983 // no entry here at this idx, so use it
3984 assert(list->capacity == 0);
3985 inst->dev_ext_disp_hash[idx].func_name =
3986 (char *)loader_instance_heap_alloc(inst, strlen(funcName) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
3987 if (inst->dev_ext_disp_hash[idx].func_name == NULL) {
3988 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3989 "loader_add_dev_ext_table: Failed to allocate memory "
3994 strncpy(inst->dev_ext_disp_hash[idx].func_name, funcName, strlen(funcName) + 1);
3998 // check for enough capacity
3999 if (list->capacity == 0) {
4000 list->index = loader_instance_heap_alloc(inst, 8 * sizeof(*(list->index)), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
4001 if (list->index == NULL) {
4002 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, "loader_add_dev_ext_table: Failed to allocate memory for list index",
4006 list->capacity = 8 * sizeof(*(list->index));
4007 } else if (list->capacity < (list->count + 1) * sizeof(*(list->index))) {
4008 void *new_ptr = loader_instance_heap_realloc(inst, list->index, list->capacity, list->capacity * 2,
4009 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
4010 if (NULL == new_ptr) {
4011 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4012 "loader_add_dev_ext_table: Failed to reallocate memory for list index", funcName);
4015 list->index = new_ptr;
4016 list->capacity *= 2;
4019 // find an unused index in the hash table and use it
4020 i = (idx + 1) % MAX_NUM_UNKNOWN_EXTS;
4022 if (!inst->dev_ext_disp_hash[i].func_name) {
4023 assert(inst->dev_ext_disp_hash[i].list.capacity == 0);
4024 inst->dev_ext_disp_hash[i].func_name =
4025 (char *)loader_instance_heap_alloc(inst, strlen(funcName) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
4026 if (inst->dev_ext_disp_hash[i].func_name == NULL) {
4027 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4028 "loader_add_dev_ext_table: Failed to allocate memory "
4033 strncpy(inst->dev_ext_disp_hash[i].func_name, funcName, strlen(funcName) + 1);
4034 list->index[list->count] = i;
4039 i = (i + 1) % MAX_NUM_UNKNOWN_EXTS;
4042 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4043 "loader_add_dev_ext_table: Could not insert into hash table; is "
4049 static bool loader_name_in_dev_ext_table(struct loader_instance *inst, uint32_t *idx, const char *funcName) {
4051 if (inst->dev_ext_disp_hash[*idx].func_name && !strcmp(inst->dev_ext_disp_hash[*idx].func_name, funcName)) return true;
4053 // funcName wasn't at the primary spot in the hash table
4054 // search the list of secondary locations (shallow search, not deep search)
4055 for (uint32_t i = 0; i < inst->dev_ext_disp_hash[*idx].list.count; i++) {
4056 alt_idx = inst->dev_ext_disp_hash[*idx].list.index[i];
4057 if (!strcmp(inst->dev_ext_disp_hash[*idx].func_name, funcName)) {
4066 // This function returns generic trampoline code address for unknown entry
4068 // Presumably, these unknown entry points (as given by funcName) are device
4069 // extension entrypoints. A hash table is used to keep a list of unknown entry
4070 // points and their mapping to the device extension dispatch table
4071 // (struct loader_dev_ext_dispatch_table).
4073 // For a given entry point string (funcName), if an existing mapping is found
4075 // trampoline address for that mapping is returned. Otherwise, this unknown
4077 // has not been seen yet. Next check if a layer or ICD supports it. If so then
4079 // new entry in the hash table is initialized and that trampoline address for
4080 // the new entry is returned. Null is returned if the hash table is full or
4081 // if no discovered layer or ICD returns a non-NULL GetProcAddr for it.
4082 void *loader_dev_ext_gpa(struct loader_instance *inst, const char *funcName) {
4086 idx = murmurhash(funcName, strlen(funcName), seed) % MAX_NUM_UNKNOWN_EXTS;
4088 if (loader_name_in_dev_ext_table(inst, &idx, funcName))
4089 // found funcName already in hash
4090 return loader_get_dev_ext_trampoline(idx);
4092 // Check if funcName is supported in either ICDs or a layer library
4093 if (!loader_check_icds_for_dev_ext_address(inst, funcName) &&
4094 !loader_check_layer_list_for_dev_ext_address(&inst->app_activated_layer_list, funcName)) {
4095 // if support found in layers continue on
4099 if (loader_add_dev_ext_table(inst, &idx, funcName)) {
4100 // successfully added new table entry
4101 // init any dev dispatch table entries as needed
4102 loader_init_dispatch_dev_ext_entry(inst, NULL, idx, funcName);
4103 return loader_get_dev_ext_trampoline(idx);
4109 static bool loader_check_icds_for_phys_dev_ext_address(struct loader_instance *inst, const char *funcName) {
4110 struct loader_icd_term *icd_term;
4111 icd_term = inst->icd_terms;
4112 while (NULL != icd_term) {
4113 if (icd_term->scanned_icd->interface_version >= MIN_PHYS_DEV_EXTENSION_ICD_INTERFACE_VERSION &&
4114 icd_term->scanned_icd->GetPhysicalDeviceProcAddr(icd_term->instance, funcName))
4115 // this icd supports funcName
4117 icd_term = icd_term->next;
4123 static bool loader_check_layer_list_for_phys_dev_ext_address(struct loader_instance *inst, const char *funcName) {
4124 struct loader_layer_properties *layer_prop_list = inst->expanded_activated_layer_list.list;
4125 for (uint32_t layer = 0; layer < inst->expanded_activated_layer_list.count; ++layer) {
4126 // If this layer supports the vk_layerGetPhysicalDeviceProcAddr, then call
4127 // it and see if it returns a valid pointer for this function name.
4128 if (layer_prop_list[layer].interface_version > 1) {
4129 const struct loader_layer_functions *const functions = &(layer_prop_list[layer].functions);
4130 if (NULL != functions->get_physical_device_proc_addr &&
4131 NULL != functions->get_physical_device_proc_addr((VkInstance)inst->instance, funcName)) {
4140 static void loader_free_phys_dev_ext_table(struct loader_instance *inst) {
4141 for (uint32_t i = 0; i < MAX_NUM_UNKNOWN_EXTS; i++) {
4142 loader_instance_heap_free(inst, inst->phys_dev_ext_disp_hash[i].func_name);
4143 loader_instance_heap_free(inst, inst->phys_dev_ext_disp_hash[i].list.index);
4145 memset(inst->phys_dev_ext_disp_hash, 0, sizeof(inst->phys_dev_ext_disp_hash));
4148 static bool loader_add_phys_dev_ext_table(struct loader_instance *inst, uint32_t *ptr_idx, const char *funcName) {
4150 uint32_t idx = *ptr_idx;
4151 struct loader_dispatch_hash_list *list = &inst->phys_dev_ext_disp_hash[idx].list;
4153 if (!inst->phys_dev_ext_disp_hash[idx].func_name) {
4154 // no entry here at this idx, so use it
4155 assert(list->capacity == 0);
4156 inst->phys_dev_ext_disp_hash[idx].func_name =
4157 (char *)loader_instance_heap_alloc(inst, strlen(funcName) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
4158 if (inst->phys_dev_ext_disp_hash[idx].func_name == NULL) {
4159 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4160 "loader_add_phys_dev_ext_table() can't allocate memory for "
4164 strncpy(inst->phys_dev_ext_disp_hash[idx].func_name, funcName, strlen(funcName) + 1);
4168 // check for enough capacity
4169 if (list->capacity == 0) {
4170 list->index = loader_instance_heap_alloc(inst, 8 * sizeof(*(list->index)), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
4171 if (list->index == NULL) {
4172 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, "loader_add_phys_dev_ext_table() can't allocate list memory");
4175 list->capacity = 8 * sizeof(*(list->index));
4176 } else if (list->capacity < (list->count + 1) * sizeof(*(list->index))) {
4177 void *new_ptr = loader_instance_heap_realloc(inst, list->index, list->capacity, list->capacity * 2,
4178 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
4179 if (NULL == new_ptr) {
4180 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, "loader_add_phys_dev_ext_table() can't reallocate list memory");
4183 list->index = new_ptr;
4184 list->capacity *= 2;
4187 // find an unused index in the hash table and use it
4188 i = (idx + 1) % MAX_NUM_UNKNOWN_EXTS;
4190 if (!inst->phys_dev_ext_disp_hash[i].func_name) {
4191 assert(inst->phys_dev_ext_disp_hash[i].list.capacity == 0);
4192 inst->phys_dev_ext_disp_hash[i].func_name =
4193 (char *)loader_instance_heap_alloc(inst, strlen(funcName) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
4194 if (inst->phys_dev_ext_disp_hash[i].func_name == NULL) {
4195 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4196 "loader_add_dev_ext_table() can't reallocate "
4197 "func_name memory");
4200 strncpy(inst->phys_dev_ext_disp_hash[i].func_name, funcName, strlen(funcName) + 1);
4201 list->index[list->count] = i;
4206 i = (i + 1) % MAX_NUM_UNKNOWN_EXTS;
4209 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4210 "loader_add_phys_dev_ext_table() couldn't insert into hash table; is "
4215 static bool loader_name_in_phys_dev_ext_table(struct loader_instance *inst, uint32_t *idx, const char *funcName) {
4217 if (inst->phys_dev_ext_disp_hash[*idx].func_name && !strcmp(inst->phys_dev_ext_disp_hash[*idx].func_name, funcName))
4220 // funcName wasn't at the primary spot in the hash table
4221 // search the list of secondary locations (shallow search, not deep search)
4222 for (uint32_t i = 0; i < inst->phys_dev_ext_disp_hash[*idx].list.count; i++) {
4223 alt_idx = inst->phys_dev_ext_disp_hash[*idx].list.index[i];
4224 if (!strcmp(inst->phys_dev_ext_disp_hash[*idx].func_name, funcName)) {
4233 // This function returns a generic trampoline and/or terminator function
4234 // address for any unknown physical device extension commands. A hash
4235 // table is used to keep a list of unknown entry points and their
4236 // mapping to the physical device extension dispatch table (struct
4237 // loader_phys_dev_ext_dispatch_table).
4238 // For a given entry point string (funcName), if an existing mapping is
4239 // found, then the trampoline address for that mapping is returned in
4240 // tramp_addr (if it is not NULL) and the terminator address for that
4241 // mapping is returned in term_addr (if it is not NULL). Otherwise,
4242 // this unknown entry point has not been seen yet.
4243 // If it has not been seen before, and perform_checking is 'true',
4244 // check if a layer or and ICD supports it. If so then a new entry in
4245 // the hash table is initialized and the trampoline and/or terminator
4246 // addresses are returned.
4247 // Null is returned if the hash table is full or if no discovered layer or
4248 // ICD returns a non-NULL GetProcAddr for it.
4249 bool loader_phys_dev_ext_gpa(struct loader_instance *inst, const char *funcName, bool perform_checking, void **tramp_addr,
4253 bool success = false;
4259 if (NULL != tramp_addr) {
4262 if (NULL != term_addr) {
4266 // We should always check to see if any ICD supports it.
4267 if (!loader_check_icds_for_phys_dev_ext_address(inst, funcName)) {
4268 // If we're not checking layers, or we are and it's not in a layer, just
4270 if (!perform_checking || !loader_check_layer_list_for_phys_dev_ext_address(inst, funcName)) {
4275 idx = murmurhash(funcName, strlen(funcName), seed) % MAX_NUM_UNKNOWN_EXTS;
4276 if (perform_checking && !loader_name_in_phys_dev_ext_table(inst, &idx, funcName)) {
4280 // Only need to add first one to get index in Instance. Others will use
4282 if (!added && loader_add_phys_dev_ext_table(inst, &idx, funcName)) {
4286 // Setup the ICD function pointers
4287 struct loader_icd_term *icd_term = inst->icd_terms;
4288 while (NULL != icd_term) {
4289 if (MIN_PHYS_DEV_EXTENSION_ICD_INTERFACE_VERSION <= icd_term->scanned_icd->interface_version &&
4290 NULL != icd_term->scanned_icd->GetPhysicalDeviceProcAddr) {
4291 icd_term->phys_dev_ext[idx] =
4292 (PFN_PhysDevExt)icd_term->scanned_icd->GetPhysicalDeviceProcAddr(icd_term->instance, funcName);
4294 // Make sure we set the instance dispatch to point to the
4295 // loader's terminator now since we can at least handle it
4297 inst->disp->phys_dev_ext[idx] = loader_get_phys_dev_ext_termin(idx);
4299 icd_term->phys_dev_ext[idx] = NULL;
4302 icd_term = icd_term->next;
4305 // Now, search for the first layer attached and query using it to get
4306 // the first entry point.
4307 for (i = 0; i < inst->expanded_activated_layer_list.count; i++) {
4308 struct loader_layer_properties *layer_prop = &inst->expanded_activated_layer_list.list[i];
4309 if (layer_prop->interface_version > 1 && NULL != layer_prop->functions.get_physical_device_proc_addr) {
4310 inst->disp->phys_dev_ext[idx] =
4311 (PFN_PhysDevExt)layer_prop->functions.get_physical_device_proc_addr((VkInstance)inst->instance, funcName);
4312 if (NULL != inst->disp->phys_dev_ext[idx]) {
4319 if (NULL != tramp_addr) {
4320 *tramp_addr = loader_get_phys_dev_ext_tramp(idx);
4323 if (NULL != term_addr) {
4324 *term_addr = loader_get_phys_dev_ext_termin(idx);
4333 struct loader_instance *loader_get_instance(const VkInstance instance) {
4334 // look up the loader_instance in our list by comparing dispatch tables, as
4335 // there is no guarantee the instance is still a loader_instance* after any
4336 // layers which wrap the instance object.
4337 const VkLayerInstanceDispatchTable *disp;
4338 struct loader_instance *ptr_instance = NULL;
4339 disp = loader_get_instance_layer_dispatch(instance);
4340 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
4341 if (&inst->disp->layer_inst_disp == disp) {
4342 ptr_instance = inst;
4346 return ptr_instance;
4349 static loader_platform_dl_handle loader_open_layer_lib(const struct loader_instance *inst, const char *chain_type,
4350 struct loader_layer_properties *prop) {
4351 if ((prop->lib_handle = loader_platform_open_library(prop->lib_name)) == NULL) {
4352 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, loader_platform_open_library_error(prop->lib_name));
4354 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Loading layer library %s", prop->lib_name);
4357 return prop->lib_handle;
4360 static void loader_close_layer_lib(const struct loader_instance *inst, struct loader_layer_properties *prop) {
4361 if (prop->lib_handle) {
4362 loader_platform_close_library(prop->lib_handle);
4363 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Unloading layer library %s", prop->lib_name);
4364 prop->lib_handle = NULL;
4368 void loader_deactivate_layers(const struct loader_instance *instance, struct loader_device *device,
4369 struct loader_layer_list *list) {
4370 // Delete instance list of enabled layers and close any layer libraries
4371 for (uint32_t i = 0; i < list->count; i++) {
4372 struct loader_layer_properties *layer_prop = &list->list[i];
4374 loader_close_layer_lib(instance, layer_prop);
4376 loader_destroy_layer_list(instance, device, list);
4379 // Go through the search_list and find any layers which match type. If layer
4380 // type match is found in then add it to ext_list.
4381 static void loader_add_implicit_layers(const struct loader_instance *inst, struct loader_layer_list *target_list,
4382 struct loader_layer_list *expanded_target_list,
4383 const struct loader_layer_list *source_list) {
4384 for (uint32_t src_layer = 0; src_layer < source_list->count; src_layer++) {
4385 const struct loader_layer_properties *prop = &source_list->list[src_layer];
4386 if (0 == (prop->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER)) {
4387 loader_add_implicit_layer(inst, prop, target_list, expanded_target_list, source_list);
4392 // Get the layer name(s) from the env_name environment variable. If layer is found in
4393 // search_list then add it to layer_list. But only add it to layer_list if type_flags matches.
4394 static void loader_add_env_layers(const struct loader_instance *inst, const enum layer_type_flags type_flags, const char *env_name,
4395 struct loader_layer_list *target_list, struct loader_layer_list *expanded_target_list,
4396 const struct loader_layer_list *source_list) {
4398 char *layer_env = loader_secure_getenv(env_name, inst);
4399 if (layer_env == NULL) {
4402 name = loader_stack_alloc(strlen(layer_env) + 1);
4406 strcpy(name, layer_env);
4408 while (name && *name) {
4409 next = loader_get_next_path(name);
4410 loader_find_layer_name_add_list(inst, name, type_flags, source_list, target_list, expanded_target_list);
4416 if (layer_env != NULL) {
4417 loader_free_getenv(layer_env, inst);
4423 VkResult loader_enable_instance_layers(struct loader_instance *inst, const VkInstanceCreateInfo *pCreateInfo,
4424 const struct loader_layer_list *instance_layers) {
4427 assert(inst && "Cannot have null instance");
4429 if (!loader_init_layer_list(inst, &inst->app_activated_layer_list)) {
4430 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4431 "loader_enable_instance_layers: Failed to initialize"
4432 " application version of the layer list");
4433 return VK_ERROR_OUT_OF_HOST_MEMORY;
4436 if (!loader_init_layer_list(inst, &inst->expanded_activated_layer_list)) {
4437 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4438 "loader_enable_instance_layers: Failed to initialize"
4439 " expanded version of the layer list");
4440 return VK_ERROR_OUT_OF_HOST_MEMORY;
4443 // Add any implicit layers first
4444 loader_add_implicit_layers(inst, &inst->app_activated_layer_list, &inst->expanded_activated_layer_list, instance_layers);
4446 // Add any layers specified via environment variable next
4447 loader_add_env_layers(inst, VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER, ENABLED_LAYERS_ENV, &inst->app_activated_layer_list,
4448 &inst->expanded_activated_layer_list, instance_layers);
4450 // Add layers specified by the application
4451 err = loader_add_layer_names_to_list(inst, &inst->app_activated_layer_list, &inst->expanded_activated_layer_list,
4452 pCreateInfo->enabledLayerCount, pCreateInfo->ppEnabledLayerNames, instance_layers);
4457 // Determine the layer interface version to use.
4458 bool loader_get_layer_interface_version(PFN_vkNegotiateLoaderLayerInterfaceVersion fp_negotiate_layer_version,
4459 VkNegotiateLayerInterface *interface_struct) {
4460 memset(interface_struct, 0, sizeof(VkNegotiateLayerInterface));
4461 interface_struct->sType = LAYER_NEGOTIATE_INTERFACE_STRUCT;
4462 interface_struct->loaderLayerInterfaceVersion = 1;
4464 if (fp_negotiate_layer_version != NULL) {
4465 // Layer supports the negotiation API, so call it with the loader's
4466 // latest version supported
4467 interface_struct->loaderLayerInterfaceVersion = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
4468 VkResult result = fp_negotiate_layer_version(interface_struct);
4470 if (result != VK_SUCCESS) {
4471 // Layer no longer supports the loader's latest interface version so
4472 // fail loading the Layer
4477 if (interface_struct->loaderLayerInterfaceVersion < MIN_SUPPORTED_LOADER_LAYER_INTERFACE_VERSION) {
4478 // Loader no longer supports the layer's latest interface version so
4479 // fail loading the layer
4486 // Given the list of layers to activate in the loader_instance
4487 // structure. This function will add a VkLayerInstanceCreateInfo
4488 // structure to the VkInstanceCreateInfo.pNext pointer.
4489 // Each activated layer will have it's own VkLayerInstanceLink
4490 // structure that tells the layer what Get*ProcAddr to call to
4491 // get function pointers to the next layer down.
4492 // Once the chain info has been created this function will
4493 // execute the CreateInstance call chain. Each layer will
4494 // then have an opportunity in it's CreateInstance function
4495 // to setup it's dispatch table when the lower layer returns
4497 // Each layer can wrap or not-wrap the returned VkInstance object
4499 // The instance chain is terminated by a loader function
4500 // that will call CreateInstance on all available ICD's and
4501 // cache those VkInstance objects for future use.
4502 VkResult loader_create_instance_chain(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
4503 struct loader_instance *inst, VkInstance *created_instance) {
4504 uint32_t activated_layers = 0;
4505 VkLayerInstanceCreateInfo chain_info;
4506 VkLayerInstanceLink *layer_instance_link_info = NULL;
4507 VkInstanceCreateInfo loader_create_info;
4510 PFN_vkGetInstanceProcAddr next_gipa = loader_gpa_instance_internal;
4511 PFN_vkGetInstanceProcAddr cur_gipa = loader_gpa_instance_internal;
4512 PFN_GetPhysicalDeviceProcAddr next_gpdpa = loader_gpdpa_instance_internal;
4513 PFN_GetPhysicalDeviceProcAddr cur_gpdpa = loader_gpdpa_instance_internal;
4515 memcpy(&loader_create_info, pCreateInfo, sizeof(VkInstanceCreateInfo));
4517 if (inst->expanded_activated_layer_list.count > 0) {
4518 chain_info.u.pLayerInfo = NULL;
4519 chain_info.pNext = pCreateInfo->pNext;
4520 chain_info.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO;
4521 chain_info.function = VK_LAYER_LINK_INFO;
4522 loader_create_info.pNext = &chain_info;
4524 layer_instance_link_info = loader_stack_alloc(sizeof(VkLayerInstanceLink) * inst->expanded_activated_layer_list.count);
4525 if (!layer_instance_link_info) {
4526 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4527 "loader_create_instance_chain: Failed to alloc Instance"
4528 " objects for layer");
4529 return VK_ERROR_OUT_OF_HOST_MEMORY;
4532 // Create instance chain of enabled layers
4533 for (int32_t i = inst->expanded_activated_layer_list.count - 1; i >= 0; i--) {
4534 struct loader_layer_properties *layer_prop = &inst->expanded_activated_layer_list.list[i];
4535 loader_platform_dl_handle lib_handle;
4537 lib_handle = loader_open_layer_lib(inst, "instance", layer_prop);
4542 if (NULL == layer_prop->functions.negotiate_layer_interface) {
4543 PFN_vkNegotiateLoaderLayerInterfaceVersion negotiate_interface = NULL;
4544 bool functions_in_interface = false;
4545 if (strlen(layer_prop->functions.str_negotiate_interface) == 0) {
4546 negotiate_interface = (PFN_vkNegotiateLoaderLayerInterfaceVersion)loader_platform_get_proc_address(
4547 lib_handle, "vkNegotiateLoaderLayerInterfaceVersion");
4549 negotiate_interface = (PFN_vkNegotiateLoaderLayerInterfaceVersion)loader_platform_get_proc_address(
4550 lib_handle, layer_prop->functions.str_negotiate_interface);
4553 // If we can negotiate an interface version, then we can also
4554 // get everything we need from the one function call, so try
4555 // that first, and see if we can get all the function pointers
4556 // necessary from that one call.
4557 if (NULL != negotiate_interface) {
4558 layer_prop->functions.negotiate_layer_interface = negotiate_interface;
4560 VkNegotiateLayerInterface interface_struct;
4562 if (loader_get_layer_interface_version(negotiate_interface, &interface_struct)) {
4563 // Go ahead and set the properties version to the
4565 layer_prop->interface_version = interface_struct.loaderLayerInterfaceVersion;
4567 // If the interface is 2 or newer, we have access to the
4568 // new GetPhysicalDeviceProcAddr function, so grab it,
4569 // and the other necessary functions, from the
4571 if (interface_struct.loaderLayerInterfaceVersion > 1) {
4572 cur_gipa = interface_struct.pfnGetInstanceProcAddr;
4573 cur_gpdpa = interface_struct.pfnGetPhysicalDeviceProcAddr;
4574 if (cur_gipa != NULL) {
4575 // We've set the functions, so make sure we
4576 // don't do the unnecessary calls later.
4577 functions_in_interface = true;
4583 if (!functions_in_interface) {
4584 if ((cur_gipa = layer_prop->functions.get_instance_proc_addr) == NULL) {
4585 if (strlen(layer_prop->functions.str_gipa) == 0) {
4587 (PFN_vkGetInstanceProcAddr)loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr");
4588 layer_prop->functions.get_instance_proc_addr = cur_gipa;
4590 cur_gipa = (PFN_vkGetInstanceProcAddr)loader_platform_get_proc_address(lib_handle,
4591 layer_prop->functions.str_gipa);
4594 if (NULL == cur_gipa) {
4595 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4596 "loader_create_instance_chain: Failed to"
4597 " find \'vkGetInstanceProcAddr\' in "
4599 layer_prop->lib_name);
4606 layer_instance_link_info[activated_layers].pNext = chain_info.u.pLayerInfo;
4607 layer_instance_link_info[activated_layers].pfnNextGetInstanceProcAddr = next_gipa;
4608 layer_instance_link_info[activated_layers].pfnNextGetPhysicalDeviceProcAddr = next_gpdpa;
4609 next_gipa = cur_gipa;
4610 if (layer_prop->interface_version > 1 && cur_gpdpa != NULL) {
4611 layer_prop->functions.get_physical_device_proc_addr = cur_gpdpa;
4612 next_gpdpa = cur_gpdpa;
4615 chain_info.u.pLayerInfo = &layer_instance_link_info[activated_layers];
4617 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "Insert instance layer %s (%s)", layer_prop->info.layerName,
4618 layer_prop->lib_name);
4624 PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)next_gipa(*created_instance, "vkCreateInstance");
4625 if (fpCreateInstance) {
4626 VkLayerInstanceCreateInfo create_info_disp;
4628 create_info_disp.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO;
4629 create_info_disp.function = VK_LOADER_DATA_CALLBACK;
4631 create_info_disp.u.pfnSetInstanceLoaderData = vkSetInstanceDispatch;
4633 create_info_disp.pNext = loader_create_info.pNext;
4634 loader_create_info.pNext = &create_info_disp;
4635 res = fpCreateInstance(&loader_create_info, pAllocator, created_instance);
4637 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4638 "loader_create_instance_chain: Failed to find "
4639 "\'vkCreateInstance\'");
4640 // Couldn't find CreateInstance function!
4641 res = VK_ERROR_INITIALIZATION_FAILED;
4644 if (res == VK_SUCCESS) {
4645 loader_init_instance_core_dispatch_table(&inst->disp->layer_inst_disp, next_gipa, *created_instance);
4646 inst->instance = *created_instance;
4652 void loader_activate_instance_layer_extensions(struct loader_instance *inst, VkInstance created_inst) {
4653 loader_init_instance_extension_dispatch_table(&inst->disp->layer_inst_disp, inst->disp->layer_inst_disp.GetInstanceProcAddr,
4657 VkResult loader_create_device_chain(const struct loader_physical_device_tramp *pd, const VkDeviceCreateInfo *pCreateInfo,
4658 const VkAllocationCallbacks *pAllocator, const struct loader_instance *inst,
4659 struct loader_device *dev) {
4660 uint32_t activated_layers = 0;
4661 VkLayerDeviceLink *layer_device_link_info;
4662 VkLayerDeviceCreateInfo chain_info;
4663 VkDeviceCreateInfo loader_create_info;
4666 PFN_vkGetDeviceProcAddr fpGDPA = NULL, nextGDPA = loader_gpa_device_internal;
4667 PFN_vkGetInstanceProcAddr fpGIPA = NULL, nextGIPA = loader_gpa_instance_internal;
4669 memcpy(&loader_create_info, pCreateInfo, sizeof(VkDeviceCreateInfo));
4671 // Before we continue, we need to find out if the KHX_device_group extension is in the enabled list. If it is, we then
4672 // need to look for the corresponding VkDeviceGroupDeviceCreateInfoKHX struct in the device list. This is because we
4673 // need to replace all the incoming physical device values (which are really loader trampoline physical device values)
4674 // with the layer/ICD version.
4675 if (inst->enabled_known_extensions.khx_device_group_creation == 1) {
4676 struct VkStructureHeader *pNext = (struct VkStructureHeader *)loader_create_info.pNext;
4677 struct VkStructureHeader *pPrev = (struct VkStructureHeader *)&loader_create_info;
4678 while (NULL != pNext) {
4679 if (VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHX == pNext->sType) {
4680 VkDeviceGroupDeviceCreateInfoKHX *cur_struct = (VkDeviceGroupDeviceCreateInfoKHX *)pNext;
4681 if (0 < cur_struct->physicalDeviceCount && NULL != cur_struct->pPhysicalDevices) {
4682 VkDeviceGroupDeviceCreateInfoKHX *temp_struct = loader_stack_alloc(sizeof(VkDeviceGroupDeviceCreateInfoKHX));
4683 VkPhysicalDevice *phys_dev_array = NULL;
4684 if (NULL == temp_struct) {
4685 return VK_ERROR_OUT_OF_HOST_MEMORY;
4687 memcpy(temp_struct, cur_struct, sizeof(VkDeviceGroupDeviceCreateInfoKHX));
4688 phys_dev_array = loader_stack_alloc(sizeof(VkPhysicalDevice) * cur_struct->physicalDeviceCount);
4689 if (NULL == phys_dev_array) {
4690 return VK_ERROR_OUT_OF_HOST_MEMORY;
4693 // Before calling down, replace the incoming physical device values (which are really loader trampoline
4694 // physical devices) with the next layer (or possibly even the terminator) physical device values.
4695 struct loader_physical_device_tramp *cur_tramp;
4696 for (uint32_t phys_dev = 0; phys_dev < cur_struct->physicalDeviceCount; phys_dev++) {
4697 cur_tramp = (struct loader_physical_device_tramp *)cur_struct->pPhysicalDevices[phys_dev];
4698 phys_dev_array[phys_dev] = cur_tramp->phys_dev;
4700 temp_struct->pPhysicalDevices = phys_dev_array;
4702 // Replace the old struct in the pNext chain with this one.
4703 pPrev->pNext = (const void *)temp_struct;
4704 pNext = (struct VkStructureHeader *)(temp_struct);
4710 pNext = (struct VkStructureHeader *)(pPrev->pNext);
4714 layer_device_link_info = loader_stack_alloc(sizeof(VkLayerDeviceLink) * dev->expanded_activated_layer_list.count);
4715 if (!layer_device_link_info) {
4716 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4717 "loader_create_device_chain: Failed to alloc Device objects"
4718 " for layer. Skipping Layer.");
4719 return VK_ERROR_OUT_OF_HOST_MEMORY;
4722 if (dev->expanded_activated_layer_list.count > 0) {
4723 chain_info.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO;
4724 chain_info.function = VK_LAYER_LINK_INFO;
4725 chain_info.u.pLayerInfo = NULL;
4726 chain_info.pNext = loader_create_info.pNext;
4727 loader_create_info.pNext = &chain_info;
4729 // Create instance chain of enabled layers
4730 for (int32_t i = dev->expanded_activated_layer_list.count - 1; i >= 0; i--) {
4731 struct loader_layer_properties *layer_prop = &dev->expanded_activated_layer_list.list[i];
4732 loader_platform_dl_handle lib_handle;
4733 bool functions_in_interface = false;
4735 lib_handle = loader_open_layer_lib(inst, "device", layer_prop);
4740 // If we can negotiate an interface version, then we can also get everything we need from the one function
4741 // call, so try that first, and see if we can get all the function pointers necessary from that one call.
4742 if (NULL == layer_prop->functions.negotiate_layer_interface) {
4743 PFN_vkNegotiateLoaderLayerInterfaceVersion negotiate_interface = NULL;
4744 if (strlen(layer_prop->functions.str_negotiate_interface) == 0) {
4745 negotiate_interface = (PFN_vkNegotiateLoaderLayerInterfaceVersion)loader_platform_get_proc_address(
4746 lib_handle, "vkNegotiateLoaderLayerInterfaceVersion");
4748 negotiate_interface = (PFN_vkNegotiateLoaderLayerInterfaceVersion)loader_platform_get_proc_address(
4749 lib_handle, layer_prop->functions.str_negotiate_interface);
4752 if (NULL != negotiate_interface) {
4753 layer_prop->functions.negotiate_layer_interface = negotiate_interface;
4755 VkNegotiateLayerInterface interface_struct;
4757 if (loader_get_layer_interface_version(negotiate_interface, &interface_struct)) {
4758 // Go ahead and set the properties version to the correct value.
4759 layer_prop->interface_version = interface_struct.loaderLayerInterfaceVersion;
4761 // If the interface is 2 or newer, we have access to the new GetPhysicalDeviceProcAddr
4762 // function, so grab it, and the other necessary functions, from the structure.
4763 if (interface_struct.loaderLayerInterfaceVersion > 1) {
4764 fpGIPA = interface_struct.pfnGetInstanceProcAddr;
4765 fpGDPA = interface_struct.pfnGetDeviceProcAddr;
4766 if (fpGIPA != NULL && fpGDPA) {
4767 // We've set the functions, so make sure we
4768 // don't do the unnecessary calls later.
4769 functions_in_interface = true;
4776 if (!functions_in_interface) {
4777 if ((fpGIPA = layer_prop->functions.get_instance_proc_addr) == NULL) {
4778 if (strlen(layer_prop->functions.str_gipa) == 0) {
4779 fpGIPA = (PFN_vkGetInstanceProcAddr)loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr");
4780 layer_prop->functions.get_instance_proc_addr = fpGIPA;
4783 (PFN_vkGetInstanceProcAddr)loader_platform_get_proc_address(lib_handle, layer_prop->functions.str_gipa);
4785 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4786 "loader_create_device_chain: Failed to find "
4787 "\'vkGetInstanceProcAddr\' in layer %s. Skipping"
4789 layer_prop->lib_name);
4793 if ((fpGDPA = layer_prop->functions.get_device_proc_addr) == NULL) {
4794 if (strlen(layer_prop->functions.str_gdpa) == 0) {
4795 fpGDPA = (PFN_vkGetDeviceProcAddr)loader_platform_get_proc_address(lib_handle, "vkGetDeviceProcAddr");
4796 layer_prop->functions.get_device_proc_addr = fpGDPA;
4799 (PFN_vkGetDeviceProcAddr)loader_platform_get_proc_address(lib_handle, layer_prop->functions.str_gdpa);
4801 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "Failed to find vkGetDeviceProcAddr in layer %s",
4802 layer_prop->lib_name);
4807 layer_device_link_info[activated_layers].pNext = chain_info.u.pLayerInfo;
4808 layer_device_link_info[activated_layers].pfnNextGetInstanceProcAddr = nextGIPA;
4809 layer_device_link_info[activated_layers].pfnNextGetDeviceProcAddr = nextGDPA;
4810 chain_info.u.pLayerInfo = &layer_device_link_info[activated_layers];
4814 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "Inserted device layer %s (%s)", layer_prop->info.layerName,
4815 layer_prop->lib_name);
4821 VkDevice created_device = (VkDevice)dev;
4822 PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)nextGIPA(inst->instance, "vkCreateDevice");
4823 if (fpCreateDevice) {
4824 VkLayerDeviceCreateInfo create_info_disp;
4826 create_info_disp.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO;
4827 create_info_disp.function = VK_LOADER_DATA_CALLBACK;
4829 create_info_disp.u.pfnSetDeviceLoaderData = vkSetDeviceDispatch;
4831 create_info_disp.pNext = loader_create_info.pNext;
4832 loader_create_info.pNext = &create_info_disp;
4833 res = fpCreateDevice(pd->phys_dev, &loader_create_info, pAllocator, &created_device);
4834 if (res != VK_SUCCESS) {
4837 dev->chain_device = created_device;
4839 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4840 "loader_create_device_chain: Failed to find \'vkCreateDevice\' "
4842 // Couldn't find CreateDevice function!
4843 return VK_ERROR_INITIALIZATION_FAILED;
4846 // Initialize device dispatch table
4847 loader_init_device_dispatch_table(&dev->loader_dispatch, nextGDPA, dev->chain_device);
4852 VkResult loader_validate_layers(const struct loader_instance *inst, const uint32_t layer_count,
4853 const char *const *ppEnabledLayerNames, const struct loader_layer_list *list) {
4854 struct loader_layer_properties *prop;
4856 for (uint32_t i = 0; i < layer_count; i++) {
4857 VkStringErrorFlags result = vk_string_validate(MaxLoaderStringLength, ppEnabledLayerNames[i]);
4858 if (result != VK_STRING_ERROR_NONE) {
4859 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4860 "loader_validate_layers: Device ppEnabledLayerNames "
4861 "contains string that is too long or is badly formed");
4862 return VK_ERROR_LAYER_NOT_PRESENT;
4865 prop = loader_get_layer_property(ppEnabledLayerNames[i], list);
4867 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4868 "loader_validate_layers: Layer %d does not exist in the list of available layers", i);
4869 return VK_ERROR_LAYER_NOT_PRESENT;
4875 VkResult loader_validate_instance_extensions(const struct loader_instance *inst, const struct loader_extension_list *icd_exts,
4876 const struct loader_layer_list *instance_layers,
4877 const VkInstanceCreateInfo *pCreateInfo) {
4878 VkExtensionProperties *extension_prop;
4880 bool check_if_known = true;
4881 VkResult res = VK_SUCCESS;
4883 struct loader_layer_list active_layers;
4884 struct loader_layer_list expanded_layers;
4885 memset(&active_layers, 0, sizeof(active_layers));
4886 memset(&expanded_layers, 0, sizeof(expanded_layers));
4887 if (!loader_init_layer_list(inst, &active_layers)) {
4888 res = VK_ERROR_OUT_OF_HOST_MEMORY;
4891 if (!loader_init_layer_list(inst, &expanded_layers)) {
4892 res = VK_ERROR_OUT_OF_HOST_MEMORY;
4896 // Build the lists of active layers (including metalayers) and expanded layers (with metalayers resolved to their components)
4897 loader_add_implicit_layers(inst, &active_layers, &expanded_layers, instance_layers);
4898 loader_add_env_layers(inst, VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER, ENABLED_LAYERS_ENV, &active_layers, &expanded_layers,
4900 res = loader_add_layer_names_to_list(inst, &active_layers, &expanded_layers, pCreateInfo->enabledLayerCount,
4901 pCreateInfo->ppEnabledLayerNames, instance_layers);
4902 if (VK_SUCCESS != res) {
4906 for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
4907 VkStringErrorFlags result = vk_string_validate(MaxLoaderStringLength, pCreateInfo->ppEnabledExtensionNames[i]);
4908 if (result != VK_STRING_ERROR_NONE) {
4909 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4910 "loader_validate_instance_extensions: Instance ppEnabledExtensionNames contains "
4911 "string that is too long or is badly formed");
4912 res = VK_ERROR_EXTENSION_NOT_PRESENT;
4916 // Check if a user wants to disable the instance extension filtering behavior
4917 env_value = loader_getenv("VK_LOADER_DISABLE_INST_EXT_FILTER", inst);
4918 if (NULL != env_value && atoi(env_value) != 0) {
4919 check_if_known = false;
4921 loader_free_getenv(env_value, inst);
4923 if (check_if_known) {
4924 // See if the extension is in the list of supported extensions
4926 for (uint32_t j = 0; LOADER_INSTANCE_EXTENSIONS[j] != NULL; j++) {
4927 if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], LOADER_INSTANCE_EXTENSIONS[j]) == 0) {
4933 // If it isn't in the list, return an error
4935 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4936 "loader_validate_instance_extensions: Extension %s not found in list of known instance extensions.",
4937 pCreateInfo->ppEnabledExtensionNames[i]);
4938 res = VK_ERROR_EXTENSION_NOT_PRESENT;
4943 extension_prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i], icd_exts);
4945 if (extension_prop) {
4949 extension_prop = NULL;
4951 // Not in global list, search expanded layer extension list
4952 for (uint32_t j = 0; NULL == extension_prop && j < expanded_layers.count; ++j) {
4954 get_extension_property(pCreateInfo->ppEnabledExtensionNames[i], &expanded_layers.list[j].instance_extension_list);
4957 if (!extension_prop) {
4958 // Didn't find extension name in any of the global layers, error out
4959 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4960 "loader_validate_instance_extensions: Instance extension %s not supported by available ICDs or enabled "
4962 pCreateInfo->ppEnabledExtensionNames[i]);
4963 res = VK_ERROR_EXTENSION_NOT_PRESENT;
4969 loader_destroy_layer_list(inst, NULL, &active_layers);
4970 loader_destroy_layer_list(inst, NULL, &expanded_layers);
4974 VkResult loader_validate_device_extensions(struct loader_physical_device_tramp *phys_dev,
4975 const struct loader_layer_list *activated_device_layers,
4976 const struct loader_extension_list *icd_exts, const VkDeviceCreateInfo *pCreateInfo) {
4977 VkExtensionProperties *extension_prop;
4978 struct loader_layer_properties *layer_prop;
4980 for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
4981 VkStringErrorFlags result = vk_string_validate(MaxLoaderStringLength, pCreateInfo->ppEnabledExtensionNames[i]);
4982 if (result != VK_STRING_ERROR_NONE) {
4983 loader_log(phys_dev->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4984 "loader_validate_device_extensions: Device ppEnabledExtensionNames contains "
4985 "string that is too long or is badly formed");
4986 return VK_ERROR_EXTENSION_NOT_PRESENT;
4989 const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
4990 extension_prop = get_extension_property(extension_name, icd_exts);
4992 if (extension_prop) {
4996 // Not in global list, search activated layer extension lists
4997 for (uint32_t j = 0; j < activated_device_layers->count; j++) {
4998 layer_prop = &activated_device_layers->list[j];
5000 extension_prop = get_dev_extension_property(extension_name, &layer_prop->device_extension_list);
5001 if (extension_prop) {
5002 // Found the extension in one of the layers enabled by the app.
5007 if (!extension_prop) {
5008 // Didn't find extension name in any of the device layers, error out
5009 loader_log(phys_dev->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5010 "loader_validate_device_extensions: Device extension %s not supported by selected physical device "
5011 "or enabled layers.",
5012 pCreateInfo->ppEnabledExtensionNames[i]);
5013 return VK_ERROR_EXTENSION_NOT_PRESENT;
5019 // Terminator functions for the Instance chain
5020 // All named terminator_<Vulakn API name>
5021 VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateInstance(const VkInstanceCreateInfo *pCreateInfo,
5022 const VkAllocationCallbacks *pAllocator, VkInstance *pInstance) {
5023 struct loader_icd_term *icd_term;
5024 VkExtensionProperties *prop;
5025 char **filtered_extension_names = NULL;
5026 VkInstanceCreateInfo icd_create_info;
5027 VkResult res = VK_SUCCESS;
5028 bool one_icd_successful = false;
5030 struct loader_instance *ptr_instance = (struct loader_instance *)*pInstance;
5031 memcpy(&icd_create_info, pCreateInfo, sizeof(icd_create_info));
5033 icd_create_info.enabledLayerCount = 0;
5034 icd_create_info.ppEnabledLayerNames = NULL;
5036 // NOTE: Need to filter the extensions to only those supported by the ICD.
5037 // No ICD will advertise support for layers. An ICD library could
5038 // support a layer, but it would be independent of the actual ICD,
5039 // just in the same library.
5040 filtered_extension_names = loader_stack_alloc(pCreateInfo->enabledExtensionCount * sizeof(char *));
5041 if (!filtered_extension_names) {
5042 loader_log(ptr_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5043 "terminator_CreateInstance: Failed create extension name array for %d extensions",
5044 pCreateInfo->enabledExtensionCount);
5045 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5048 icd_create_info.ppEnabledExtensionNames = (const char *const *)filtered_extension_names;
5050 for (uint32_t i = 0; i < ptr_instance->icd_tramp_list.count; i++) {
5051 icd_term = loader_icd_add(ptr_instance, &ptr_instance->icd_tramp_list.scanned_list[i]);
5052 if (NULL == icd_term) {
5053 loader_log(ptr_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5054 "terminator_CreateInstance: Failed to add ICD %d to ICD trampoline list.", i);
5055 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5059 // If any error happens after here, we need to remove the ICD from the list,
5060 // because we've already added it, but haven't validated it
5062 icd_create_info.enabledExtensionCount = 0;
5063 struct loader_extension_list icd_exts;
5065 loader_log(ptr_instance, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Build ICD instance extension list");
5066 // traverse scanned icd list adding non-duplicate extensions to the list
5067 res = loader_init_generic_list(ptr_instance, (struct loader_generic_list *)&icd_exts, sizeof(VkExtensionProperties));
5068 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
5069 // If out of memory, bail immediately.
5071 } else if (VK_SUCCESS != res) {
5072 // Something bad happened with this ICD, so free it and try the
5074 ptr_instance->icd_terms = icd_term->next;
5075 icd_term->next = NULL;
5076 loader_icd_destroy(ptr_instance, icd_term, pAllocator);
5080 res = loader_add_instance_extensions(ptr_instance, icd_term->scanned_icd->EnumerateInstanceExtensionProperties,
5081 icd_term->scanned_icd->lib_name, &icd_exts);
5082 if (VK_SUCCESS != res) {
5083 loader_destroy_generic_list(ptr_instance, (struct loader_generic_list *)&icd_exts);
5084 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
5085 // If out of memory, bail immediately.
5088 // Something bad happened with this ICD, so free it and try the next.
5089 ptr_instance->icd_terms = icd_term->next;
5090 icd_term->next = NULL;
5091 loader_icd_destroy(ptr_instance, icd_term, pAllocator);
5096 for (uint32_t j = 0; j < pCreateInfo->enabledExtensionCount; j++) {
5097 prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[j], &icd_exts);
5099 filtered_extension_names[icd_create_info.enabledExtensionCount] = (char *)pCreateInfo->ppEnabledExtensionNames[j];
5100 icd_create_info.enabledExtensionCount++;
5104 loader_destroy_generic_list(ptr_instance, (struct loader_generic_list *)&icd_exts);
5106 VkResult icd_result =
5107 ptr_instance->icd_tramp_list.scanned_list[i].CreateInstance(&icd_create_info, pAllocator, &(icd_term->instance));
5108 if (VK_ERROR_OUT_OF_HOST_MEMORY == icd_result) {
5109 // If out of memory, bail immediately.
5110 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5112 } else if (VK_SUCCESS != icd_result) {
5113 loader_log(ptr_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
5114 "terminator_CreateInstance: Failed to CreateInstance in "
5115 "ICD %d. Skipping ICD.",
5117 ptr_instance->icd_terms = icd_term->next;
5118 icd_term->next = NULL;
5119 loader_icd_destroy(ptr_instance, icd_term, pAllocator);
5123 if (!loader_icd_init_entries(icd_term, icd_term->instance,
5124 ptr_instance->icd_tramp_list.scanned_list[i].GetInstanceProcAddr)) {
5125 loader_log(ptr_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
5126 "terminator_CreateInstance: Failed to CreateInstance and find "
5127 "entrypoints with ICD. Skipping ICD.");
5128 ptr_instance->icd_terms = icd_term->next;
5129 icd_term->next = NULL;
5130 loader_icd_destroy(ptr_instance, icd_term, pAllocator);
5134 // If we made it this far, at least one ICD was successful
5135 one_icd_successful = true;
5138 // If no ICDs were added to instance list and res is unchanged from it's initial value, the loader was unable to
5139 // find a suitable ICD.
5140 if (VK_SUCCESS == res && (ptr_instance->icd_terms == NULL || !one_icd_successful)) {
5141 res = VK_ERROR_INCOMPATIBLE_DRIVER;
5146 if (VK_SUCCESS != res) {
5147 while (NULL != ptr_instance->icd_terms) {
5148 icd_term = ptr_instance->icd_terms;
5149 ptr_instance->icd_terms = icd_term->next;
5150 if (NULL != icd_term->instance) {
5151 icd_term->dispatch.DestroyInstance(icd_term->instance, pAllocator);
5153 loader_icd_destroy(ptr_instance, icd_term, pAllocator);
5160 VKAPI_ATTR void VKAPI_CALL terminator_DestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
5161 struct loader_instance *ptr_instance = loader_instance(instance);
5162 if (NULL == ptr_instance) {
5165 struct loader_icd_term *icd_terms = ptr_instance->icd_terms;
5166 struct loader_icd_term *next_icd_term;
5168 // Remove this instance from the list of instances:
5169 struct loader_instance *prev = NULL;
5170 struct loader_instance *next = loader.instances;
5171 while (next != NULL) {
5172 if (next == ptr_instance) {
5173 // Remove this instance from the list:
5175 prev->next = next->next;
5177 loader.instances = next->next;
5184 while (NULL != icd_terms) {
5185 if (icd_terms->instance) {
5186 icd_terms->dispatch.DestroyInstance(icd_terms->instance, pAllocator);
5188 next_icd_term = icd_terms->next;
5189 icd_terms->instance = VK_NULL_HANDLE;
5190 loader_icd_destroy(ptr_instance, icd_terms, pAllocator);
5192 icd_terms = next_icd_term;
5195 loader_delete_layer_properties(ptr_instance, &ptr_instance->instance_layer_list);
5196 loader_scanned_icd_clear(ptr_instance, &ptr_instance->icd_tramp_list);
5197 loader_destroy_generic_list(ptr_instance, (struct loader_generic_list *)&ptr_instance->ext_list);
5198 if (NULL != ptr_instance->phys_devs_term) {
5199 for (uint32_t i = 0; i < ptr_instance->phys_dev_count_term; i++) {
5200 loader_instance_heap_free(ptr_instance, ptr_instance->phys_devs_term[i]);
5202 loader_instance_heap_free(ptr_instance, ptr_instance->phys_devs_term);
5204 if (NULL != ptr_instance->phys_dev_groups_term) {
5205 for (uint32_t i = 0; i < ptr_instance->phys_dev_group_count_term; i++) {
5206 loader_instance_heap_free(ptr_instance, ptr_instance->phys_dev_groups_term[i]);
5208 loader_instance_heap_free(ptr_instance, ptr_instance->phys_dev_groups_term);
5210 loader_free_dev_ext_table(ptr_instance);
5211 loader_free_phys_dev_ext_table(ptr_instance);
5214 VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo,
5215 const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
5216 VkResult res = VK_SUCCESS;
5217 struct loader_physical_device_term *phys_dev_term;
5218 phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
5219 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
5221 struct loader_device *dev = (struct loader_device *)*pDevice;
5222 PFN_vkCreateDevice fpCreateDevice = icd_term->dispatch.CreateDevice;
5223 struct loader_extension_list icd_exts;
5225 struct VkStructureHeader *caller_dgci_container = NULL;
5226 VkDeviceGroupDeviceCreateInfoKHX *caller_dgci = NULL;
5228 dev->phys_dev_term = phys_dev_term;
5230 icd_exts.list = NULL;
5232 if (fpCreateDevice == NULL) {
5233 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5234 "terminator_CreateDevice: No vkCreateDevice command exposed "
5236 icd_term->scanned_icd->lib_name);
5237 res = VK_ERROR_INITIALIZATION_FAILED;
5241 VkDeviceCreateInfo localCreateInfo;
5242 memcpy(&localCreateInfo, pCreateInfo, sizeof(localCreateInfo));
5244 // NOTE: Need to filter the extensions to only those supported by the ICD.
5245 // No ICD will advertise support for layers. An ICD library could support a layer,
5246 // but it would be independent of the actual ICD, just in the same library.
5247 char **filtered_extension_names = NULL;
5248 if (0 < pCreateInfo->enabledExtensionCount) {
5249 filtered_extension_names = loader_stack_alloc(pCreateInfo->enabledExtensionCount * sizeof(char *));
5250 if (NULL == filtered_extension_names) {
5251 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5252 "terminator_CreateDevice: Failed to create extension name "
5253 "storage for %d extensions %d",
5254 pCreateInfo->enabledExtensionCount);
5255 return VK_ERROR_OUT_OF_HOST_MEMORY;
5259 localCreateInfo.enabledLayerCount = 0;
5260 localCreateInfo.ppEnabledLayerNames = NULL;
5262 localCreateInfo.enabledExtensionCount = 0;
5263 localCreateInfo.ppEnabledExtensionNames = (const char *const *)filtered_extension_names;
5265 // Get the physical device (ICD) extensions
5266 res = loader_init_generic_list(icd_term->this_instance, (struct loader_generic_list *)&icd_exts, sizeof(VkExtensionProperties));
5267 if (VK_SUCCESS != res) {
5271 res = loader_add_device_extensions(icd_term->this_instance, icd_term->dispatch.EnumerateDeviceExtensionProperties,
5272 phys_dev_term->phys_dev, icd_term->scanned_icd->lib_name, &icd_exts);
5273 if (res != VK_SUCCESS) {
5277 for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
5278 const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
5279 VkExtensionProperties *prop = get_extension_property(extension_name, &icd_exts);
5281 filtered_extension_names[localCreateInfo.enabledExtensionCount] = (char *)extension_name;
5282 localCreateInfo.enabledExtensionCount++;
5284 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
5285 "vkCreateDevice extension %s not available for "
5286 "devices associated with ICD %s",
5287 extension_name, icd_term->scanned_icd->lib_name);
5291 // Before we continue, If KHX_device_group is the list of enabled and viable extensions, then we then need to look for the
5292 // corresponding VkDeviceGroupDeviceCreateInfoKHX struct in the device list and replace all the physical device values (which
5293 // are really loader physical device terminator values) with the ICD versions.
5294 if (icd_term->this_instance->enabled_known_extensions.khx_device_group_creation == 1) {
5295 struct VkStructureHeader *pNext = (struct VkStructureHeader *)localCreateInfo.pNext;
5296 struct VkStructureHeader *pPrev = (struct VkStructureHeader *)&localCreateInfo;
5297 while (NULL != pNext) {
5298 if (VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHX == pNext->sType) {
5299 VkDeviceGroupDeviceCreateInfoKHX *cur_struct = (VkDeviceGroupDeviceCreateInfoKHX *)pNext;
5300 if (0 < cur_struct->physicalDeviceCount && NULL != cur_struct->pPhysicalDevices) {
5301 VkDeviceGroupDeviceCreateInfoKHX *temp_struct = loader_stack_alloc(sizeof(VkDeviceGroupDeviceCreateInfoKHX));
5302 VkPhysicalDevice *phys_dev_array = NULL;
5303 if (NULL == temp_struct) {
5304 return VK_ERROR_OUT_OF_HOST_MEMORY;
5306 memcpy(temp_struct, cur_struct, sizeof(VkDeviceGroupDeviceCreateInfoKHX));
5307 phys_dev_array = loader_stack_alloc(sizeof(VkPhysicalDevice) * cur_struct->physicalDeviceCount);
5308 if (NULL == phys_dev_array) {
5309 return VK_ERROR_OUT_OF_HOST_MEMORY;
5312 // Before calling down, replace the incoming physical device values (which are really loader terminator
5313 // physical devices) with the ICDs physical device values.
5314 struct loader_physical_device_term *cur_term;
5315 for (uint32_t phys_dev = 0; phys_dev < cur_struct->physicalDeviceCount; phys_dev++) {
5316 cur_term = (struct loader_physical_device_term *)cur_struct->pPhysicalDevices[phys_dev];
5317 phys_dev_array[phys_dev] = cur_term->phys_dev;
5319 temp_struct->pPhysicalDevices = phys_dev_array;
5321 // Keep track of pointers to restore pNext chain before returning
5322 caller_dgci_container = pPrev;
5323 caller_dgci = cur_struct;
5325 // Replace the old struct in the pNext chain with this one.
5326 pPrev->pNext = (const void *)temp_struct;
5327 pNext = (struct VkStructureHeader *)(temp_struct);
5333 pNext = (struct VkStructureHeader *)(pPrev->pNext);
5337 // Handle loader emulation for structs that are not supported by the ICD:
5338 // Presently, the emulation leaves the pNext chain alone. This means that the ICD will receive items in the chain which
5339 // are not recognized by the ICD. If this causes the ICD to fail, then the items would have to be removed here. The current
5340 // implementation does not remove them because copying the pNext chain would be impossible if the loader does not recognize
5341 // the any of the struct types, as the loader would not know the size to allocate and copy.
5342 if (icd_term->dispatch.GetPhysicalDeviceFeatures2KHR == NULL) {
5343 const void *pNext = localCreateInfo.pNext;
5344 while (pNext != NULL) {
5345 switch (*(VkStructureType *)pNext) {
5346 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR: {
5347 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
5348 "vkCreateDevice: Emulating handling of VkPhysicalDeviceFeatures2KHR in pNext chain for ICD \"%s\"",
5349 icd_term->scanned_icd->lib_name);
5350 const VkPhysicalDeviceFeatures2KHR *features = pNext;
5352 // Verify that VK_KHR_get_physical_device_properties2 is enabled
5353 if (icd_term->this_instance->enabled_known_extensions.khr_get_physical_device_properties2) {
5354 localCreateInfo.pEnabledFeatures = &features->features;
5357 // Leave this item in the pNext chain for now
5359 pNext = features->pNext;
5363 case VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHX: {
5365 icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
5366 "vkCreateDevice: Emulating handling of VkDeviceGroupDeviceCreateInfoKHX in pNext chain for ICD \"%s\"",
5367 icd_term->scanned_icd->lib_name);
5368 const VkDeviceGroupDeviceCreateInfoKHX *group_info = pNext;
5370 // The group must contain only this one device, since physical device groups aren't actually supported
5371 if (group_info->physicalDeviceCount != 1 || group_info->pPhysicalDevices[0] != physicalDevice) {
5372 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5373 "vkCreateDevice: Emulation failed to create device from device group info");
5374 res = VK_ERROR_INITIALIZATION_FAILED;
5378 // Nothing needs to be done here because we're leaving the item in the pNext chain and because the spec states
5379 // that the physicalDevice argument must be included in the device group, and we've already checked that it is
5381 pNext = group_info->pNext;
5385 // Multiview properties are also allowed, but since VK_KHX_multiview is a device extension, we'll just let the ICD
5386 // handle that error when the user enables the extension here
5388 const struct VkStructureHeader *header = pNext;
5389 pNext = header->pNext;
5396 res = fpCreateDevice(phys_dev_term->phys_dev, &localCreateInfo, pAllocator, &dev->icd_device);
5397 if (res != VK_SUCCESS) {
5398 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5399 "terminator_CreateDevice: Failed in ICD %s vkCreateDevice"
5401 icd_term->scanned_icd->lib_name);
5405 *pDevice = dev->icd_device;
5406 loader_add_logical_device(icd_term->this_instance, icd_term, dev);
5408 // Init dispatch pointer in new device object
5409 loader_init_dispatch(*pDevice, &dev->loader_dispatch);
5412 if (NULL != icd_exts.list) {
5413 loader_destroy_generic_list(icd_term->this_instance, (struct loader_generic_list *)&icd_exts);
5416 // Restore pNext pointer to old VkDeviceGroupDeviceCreateInfoKHX
5417 // in the chain to maintain consistency for the caller.
5418 if (caller_dgci_container != NULL) {
5419 caller_dgci_container->pNext = caller_dgci;
5425 VkResult setupLoaderTrampPhysDevs(VkInstance instance) {
5426 VkResult res = VK_SUCCESS;
5427 VkPhysicalDevice *local_phys_devs = NULL;
5428 struct loader_instance *inst;
5429 uint32_t total_count = 0;
5430 struct loader_physical_device_tramp **new_phys_devs = NULL;
5432 inst = loader_get_instance(instance);
5434 res = VK_ERROR_INITIALIZATION_FAILED;
5438 // Query how many GPUs there
5439 res = inst->disp->layer_inst_disp.EnumeratePhysicalDevices(instance, &total_count, NULL);
5440 if (res != VK_SUCCESS) {
5441 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5442 "setupLoaderTrampPhysDevs: Failed during dispatch call "
5443 "of \'vkEnumeratePhysicalDevices\' to lower layers or "
5444 "loader to get count.");
5448 // Really use what the total GPU count is since Optimus and other layers may mess
5450 total_count = inst->total_gpu_count;
5452 // Create an array for the new physical devices, which will be stored
5453 // in the instance for the trampoline code.
5454 new_phys_devs = (struct loader_physical_device_tramp **)loader_instance_heap_alloc(
5455 inst, total_count * sizeof(struct loader_physical_device_tramp *), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
5456 if (NULL == new_phys_devs) {
5457 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5458 "setupLoaderTrampPhysDevs: Failed to allocate new physical device"
5459 " array of size %d",
5461 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5464 memset(new_phys_devs, 0, total_count * sizeof(struct loader_physical_device_tramp *));
5466 // Create a temporary array (on the stack) to keep track of the
5467 // returned VkPhysicalDevice values.
5468 local_phys_devs = loader_stack_alloc(sizeof(VkPhysicalDevice) * total_count);
5469 if (NULL == local_phys_devs) {
5470 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5471 "setupLoaderTrampPhysDevs: Failed to allocate local "
5472 "physical device array of size %d",
5474 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5477 memset(local_phys_devs, 0, sizeof(VkPhysicalDevice) * total_count);
5479 res = inst->disp->layer_inst_disp.EnumeratePhysicalDevices(instance, &total_count, local_phys_devs);
5480 if (VK_SUCCESS != res) {
5481 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5482 "setupLoaderTrampPhysDevs: Failed during dispatch call "
5483 "of \'vkEnumeratePhysicalDevices\' to lower layers or "
5484 "loader to get content.");
5488 // Copy or create everything to fill the new array of physical devices
5489 for (uint32_t new_idx = 0; new_idx < total_count; new_idx++) {
5490 // Check if this physical device is already in the old buffer
5491 for (uint32_t old_idx = 0; old_idx < inst->phys_dev_count_tramp; old_idx++) {
5492 if (local_phys_devs[new_idx] == inst->phys_devs_tramp[old_idx]->phys_dev) {
5493 new_phys_devs[new_idx] = inst->phys_devs_tramp[old_idx];
5498 // If this physical device isn't in the old buffer, create it
5499 if (NULL == new_phys_devs[new_idx]) {
5500 new_phys_devs[new_idx] = (struct loader_physical_device_tramp *)loader_instance_heap_alloc(
5501 inst, sizeof(struct loader_physical_device_tramp), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
5502 if (NULL == new_phys_devs[new_idx]) {
5503 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5504 "setupLoaderTrampPhysDevs: Failed to allocate "
5505 "physical device trampoline object %d",
5507 total_count = new_idx;
5508 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5512 // Initialize the new physicalDevice object
5513 loader_set_dispatch((void *)new_phys_devs[new_idx], inst->disp);
5514 new_phys_devs[new_idx]->this_instance = inst;
5515 new_phys_devs[new_idx]->phys_dev = local_phys_devs[new_idx];
5521 if (VK_SUCCESS != res) {
5522 if (NULL != new_phys_devs) {
5523 for (uint32_t i = 0; i < total_count; i++) {
5524 loader_instance_heap_free(inst, new_phys_devs[i]);
5526 loader_instance_heap_free(inst, new_phys_devs);
5530 // Free everything that didn't carry over to the new array of
5532 if (NULL != inst->phys_devs_tramp) {
5533 for (uint32_t i = 0; i < inst->phys_dev_count_tramp; i++) {
5535 for (uint32_t j = 0; j < total_count; j++) {
5536 if (inst->phys_devs_tramp[i] == new_phys_devs[j]) {
5542 loader_instance_heap_free(inst, inst->phys_devs_tramp[i]);
5545 loader_instance_heap_free(inst, inst->phys_devs_tramp);
5548 // Swap in the new physical device list
5549 inst->phys_dev_count_tramp = total_count;
5550 inst->phys_devs_tramp = new_phys_devs;
5556 VkResult setupLoaderTermPhysDevs(struct loader_instance *inst) {
5557 VkResult res = VK_SUCCESS;
5558 struct loader_icd_term *icd_term;
5559 struct loader_phys_dev_per_icd *icd_phys_dev_array = NULL;
5560 struct loader_physical_device_term **new_phys_devs = NULL;
5562 inst->total_gpu_count = 0;
5564 // Allocate something to store the physical device characteristics
5565 // that we read from each ICD.
5566 icd_phys_dev_array =
5567 (struct loader_phys_dev_per_icd *)loader_stack_alloc(sizeof(struct loader_phys_dev_per_icd) * inst->total_icd_count);
5568 if (NULL == icd_phys_dev_array) {
5569 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5570 "setupLoaderTermPhysDevs: Failed to allocate temporary "
5571 "ICD Physical device info array of size %d",
5572 inst->total_gpu_count);
5573 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5576 memset(icd_phys_dev_array, 0, sizeof(struct loader_phys_dev_per_icd) * inst->total_icd_count);
5577 icd_term = inst->icd_terms;
5579 // For each ICD, query the number of physical devices, and then get an
5580 // internal value for those physical devices.
5581 for (uint32_t icd_idx = 0; NULL != icd_term; icd_term = icd_term->next, icd_idx++) {
5582 res = icd_term->dispatch.EnumeratePhysicalDevices(icd_term->instance, &icd_phys_dev_array[icd_idx].count, NULL);
5583 if (VK_SUCCESS != res) {
5584 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5585 "setupLoaderTermPhysDevs: Call to "
5586 "ICD %d's \'vkEnumeratePhysicalDevices\' failed with"
5592 icd_phys_dev_array[icd_idx].phys_devs =
5593 (VkPhysicalDevice *)loader_stack_alloc(icd_phys_dev_array[icd_idx].count * sizeof(VkPhysicalDevice));
5594 if (NULL == icd_phys_dev_array[icd_idx].phys_devs) {
5595 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5596 "setupLoaderTermPhysDevs: Failed to allocate temporary "
5597 "ICD Physical device array for ICD %d of size %d",
5598 icd_idx, inst->total_gpu_count);
5599 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5603 res = icd_term->dispatch.EnumeratePhysicalDevices(icd_term->instance, &(icd_phys_dev_array[icd_idx].count),
5604 icd_phys_dev_array[icd_idx].phys_devs);
5605 if (VK_SUCCESS != res) {
5608 inst->total_gpu_count += icd_phys_dev_array[icd_idx].count;
5609 icd_phys_dev_array[icd_idx].this_icd_term = icd_term;
5612 if (0 == inst->total_gpu_count) {
5613 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5614 "setupLoaderTermPhysDevs: Failed to detect any valid"
5615 " GPUs in the current config");
5616 res = VK_ERROR_INITIALIZATION_FAILED;
5620 new_phys_devs = loader_instance_heap_alloc(inst, sizeof(struct loader_physical_device_term *) * inst->total_gpu_count,
5621 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
5622 if (NULL == new_phys_devs) {
5623 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5624 "setupLoaderTermPhysDevs: Failed to allocate new physical"
5625 " device array of size %d",
5626 inst->total_gpu_count);
5627 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5630 memset(new_phys_devs, 0, sizeof(struct loader_physical_device_term *) * inst->total_gpu_count);
5632 // Copy or create everything to fill the new array of physical devices
5634 for (uint32_t icd_idx = 0; icd_idx < inst->total_icd_count; icd_idx++) {
5635 for (uint32_t pd_idx = 0; pd_idx < icd_phys_dev_array[icd_idx].count; pd_idx++) {
5636 // Check if this physical device is already in the old buffer
5637 if (NULL != inst->phys_devs_term) {
5638 for (uint32_t old_idx = 0; old_idx < inst->phys_dev_count_term; old_idx++) {
5639 if (icd_phys_dev_array[icd_idx].phys_devs[pd_idx] == inst->phys_devs_term[old_idx]->phys_dev) {
5640 new_phys_devs[idx] = inst->phys_devs_term[old_idx];
5645 // If this physical device isn't in the old buffer, then we
5646 // need to create it.
5647 if (NULL == new_phys_devs[idx]) {
5648 new_phys_devs[idx] = loader_instance_heap_alloc(inst, sizeof(struct loader_physical_device_term),
5649 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
5650 if (NULL == new_phys_devs[idx]) {
5651 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5652 "setupLoaderTermPhysDevs: Failed to allocate "
5653 "physical device terminator object %d",
5655 inst->total_gpu_count = idx;
5656 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5660 loader_set_dispatch((void *)new_phys_devs[idx], inst->disp);
5661 new_phys_devs[idx]->this_icd_term = icd_phys_dev_array[icd_idx].this_icd_term;
5662 new_phys_devs[idx]->icd_index = (uint8_t)(icd_idx);
5663 new_phys_devs[idx]->phys_dev = icd_phys_dev_array[icd_idx].phys_devs[pd_idx];
5671 if (VK_SUCCESS != res) {
5672 if (NULL != new_phys_devs) {
5673 // We've encountered an error, so we should free the new buffers.
5674 for (uint32_t i = 0; i < inst->total_gpu_count; i++) {
5675 loader_instance_heap_free(inst, new_phys_devs[i]);
5677 loader_instance_heap_free(inst, new_phys_devs);
5679 inst->total_gpu_count = 0;
5681 // Free everything that didn't carry over to the new array of
5682 // physical devices. Everything else will have been copied over
5683 // to the new array.
5684 if (NULL != inst->phys_devs_term) {
5685 for (uint32_t cur_pd = 0; cur_pd < inst->phys_dev_count_term; cur_pd++) {
5687 for (uint32_t new_pd_idx = 0; new_pd_idx < inst->total_gpu_count; new_pd_idx++) {
5688 if (inst->phys_devs_term[cur_pd] == new_phys_devs[new_pd_idx]) {
5694 loader_instance_heap_free(inst, inst->phys_devs_term[cur_pd]);
5697 loader_instance_heap_free(inst, inst->phys_devs_term);
5700 // Swap out old and new devices list
5701 inst->phys_dev_count_term = inst->total_gpu_count;
5702 inst->phys_devs_term = new_phys_devs;
5708 VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount,
5709 VkPhysicalDevice *pPhysicalDevices) {
5710 struct loader_instance *inst = (struct loader_instance *)instance;
5711 VkResult res = VK_SUCCESS;
5713 // Always call the setup loader terminator physical devices because they may
5714 // have changed at any point.
5715 res = setupLoaderTermPhysDevs(inst);
5716 if (VK_SUCCESS != res) {
5720 uint32_t copy_count = inst->total_gpu_count;
5721 if (NULL != pPhysicalDevices) {
5722 if (copy_count > *pPhysicalDeviceCount) {
5723 copy_count = *pPhysicalDeviceCount;
5724 res = VK_INCOMPLETE;
5727 for (uint32_t i = 0; i < copy_count; i++) {
5728 pPhysicalDevices[i] = (VkPhysicalDevice)inst->phys_devs_term[i];
5732 *pPhysicalDeviceCount = copy_count;
5739 VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice,
5740 VkPhysicalDeviceProperties *pProperties) {
5741 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
5742 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
5743 if (NULL != icd_term->dispatch.GetPhysicalDeviceProperties) {
5744 icd_term->dispatch.GetPhysicalDeviceProperties(phys_dev_term->phys_dev, pProperties);
5748 VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice,
5749 uint32_t *pQueueFamilyPropertyCount,
5750 VkQueueFamilyProperties *pProperties) {
5751 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
5752 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
5753 if (NULL != icd_term->dispatch.GetPhysicalDeviceQueueFamilyProperties) {
5754 icd_term->dispatch.GetPhysicalDeviceQueueFamilyProperties(phys_dev_term->phys_dev, pQueueFamilyPropertyCount, pProperties);
5758 VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice,
5759 VkPhysicalDeviceMemoryProperties *pProperties) {
5760 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
5761 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
5762 if (NULL != icd_term->dispatch.GetPhysicalDeviceMemoryProperties) {
5763 icd_term->dispatch.GetPhysicalDeviceMemoryProperties(phys_dev_term->phys_dev, pProperties);
5767 VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice,
5768 VkPhysicalDeviceFeatures *pFeatures) {
5769 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
5770 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
5771 if (NULL != icd_term->dispatch.GetPhysicalDeviceFeatures) {
5772 icd_term->dispatch.GetPhysicalDeviceFeatures(phys_dev_term->phys_dev, pFeatures);
5776 VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format,
5777 VkFormatProperties *pFormatInfo) {
5778 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
5779 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
5780 if (NULL != icd_term->dispatch.GetPhysicalDeviceFormatProperties) {
5781 icd_term->dispatch.GetPhysicalDeviceFormatProperties(phys_dev_term->phys_dev, format, pFormatInfo);
5785 VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format,
5786 VkImageType type, VkImageTiling tiling,
5787 VkImageUsageFlags usage, VkImageCreateFlags flags,
5788 VkImageFormatProperties *pImageFormatProperties) {
5789 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
5790 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
5791 if (NULL == icd_term->dispatch.GetPhysicalDeviceImageFormatProperties) {
5792 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5793 "Encountered the vkEnumerateDeviceLayerProperties "
5794 "terminator. This means a layer improperly continued.");
5795 return VK_ERROR_INITIALIZATION_FAILED;
5797 return icd_term->dispatch.GetPhysicalDeviceImageFormatProperties(phys_dev_term->phys_dev, format, type, tiling, usage, flags,
5798 pImageFormatProperties);
5801 VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceSparseImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format,
5802 VkImageType type, VkSampleCountFlagBits samples,
5803 VkImageUsageFlags usage, VkImageTiling tiling,
5804 uint32_t *pNumProperties,
5805 VkSparseImageFormatProperties *pProperties) {
5806 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
5807 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
5808 if (NULL != icd_term->dispatch.GetPhysicalDeviceSparseImageFormatProperties) {
5809 icd_term->dispatch.GetPhysicalDeviceSparseImageFormatProperties(phys_dev_term->phys_dev, format, type, samples, usage,
5810 tiling, pNumProperties, pProperties);
5814 VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
5815 const char *pLayerName, uint32_t *pPropertyCount,
5816 VkExtensionProperties *pProperties) {
5817 struct loader_physical_device_term *phys_dev_term;
5819 struct loader_layer_list implicit_layer_list = {0};
5820 struct loader_extension_list all_exts = {0};
5821 struct loader_extension_list icd_exts = {0};
5823 assert(pLayerName == NULL || strlen(pLayerName) == 0);
5825 // Any layer or trampoline wrapping should be removed at this point in time can just cast to the expected
5826 // type for VkPhysicalDevice.
5827 phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
5829 // This case is during the call down the instance chain with pLayerName == NULL
5830 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
5831 uint32_t icd_ext_count = *pPropertyCount;
5834 // Get the available device extensions
5835 res = icd_term->dispatch.EnumerateDeviceExtensionProperties(phys_dev_term->phys_dev, NULL, &icd_ext_count, pProperties);
5836 if (res != VK_SUCCESS) {
5840 if (!loader_init_layer_list(icd_term->this_instance, &implicit_layer_list)) {
5841 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5845 loader_add_implicit_layers(icd_term->this_instance, &implicit_layer_list, NULL, &icd_term->this_instance->instance_layer_list);
5846 // We need to determine which implicit layers are active, and then add their extensions. This can't be cached as
5847 // it depends on results of environment variables (which can change).
5848 if (pProperties != NULL) {
5849 // Initialize dev_extension list within the physicalDevice object
5850 res = loader_init_device_extensions(icd_term->this_instance, phys_dev_term, icd_ext_count, pProperties, &icd_exts);
5851 if (res != VK_SUCCESS) {
5855 // We need to determine which implicit layers are active, and then add their extensions. This can't be cached as
5856 // it depends on results of environment variables (which can change).
5857 res = loader_add_to_ext_list(icd_term->this_instance, &all_exts, icd_exts.count, icd_exts.list);
5858 if (res != VK_SUCCESS) {
5862 loader_add_implicit_layers(icd_term->this_instance, &implicit_layer_list, NULL,
5863 &icd_term->this_instance->instance_layer_list);
5865 for (uint32_t i = 0; i < implicit_layer_list.count; i++) {
5866 for (uint32_t j = 0; j < implicit_layer_list.list[i].device_extension_list.count; j++) {
5867 res = loader_add_to_ext_list(icd_term->this_instance, &all_exts, 1,
5868 &implicit_layer_list.list[i].device_extension_list.list[j].props);
5869 if (res != VK_SUCCESS) {
5874 uint32_t capacity = *pPropertyCount;
5875 VkExtensionProperties *props = pProperties;
5877 for (uint32_t i = 0; i < all_exts.count && i < capacity; i++) {
5878 props[i] = all_exts.list[i];
5881 // Wasn't enough space for the extensions, we did partial copy now return VK_INCOMPLETE
5882 if (capacity < all_exts.count) {
5883 res = VK_INCOMPLETE;
5885 *pPropertyCount = all_exts.count;
5888 // Just return the count; need to add in the count of implicit layer extensions
5889 // don't worry about duplicates being added in the count
5890 *pPropertyCount = icd_ext_count;
5892 for (uint32_t i = 0; i < implicit_layer_list.count; i++) {
5893 *pPropertyCount += implicit_layer_list.list[i].device_extension_list.count;
5900 if (NULL != implicit_layer_list.list) {
5901 loader_destroy_generic_list(icd_term->this_instance, (struct loader_generic_list *)&implicit_layer_list);
5903 if (NULL != all_exts.list) {
5904 loader_destroy_generic_list(icd_term->this_instance, (struct loader_generic_list *)&all_exts);
5906 if (NULL != icd_exts.list) {
5907 loader_destroy_generic_list(icd_term->this_instance, (struct loader_generic_list *)&icd_exts);
5913 VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount,
5914 VkLayerProperties *pProperties) {
5915 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
5916 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
5917 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5918 "Encountered the vkEnumerateDeviceLayerProperties "
5919 "terminator. This means a layer improperly continued.");
5920 // Should never get here this call isn't dispatched down the chain
5921 return VK_ERROR_INITIALIZATION_FAILED;
5924 VkStringErrorFlags vk_string_validate(const int max_length, const char *utf8) {
5925 VkStringErrorFlags result = VK_STRING_ERROR_NONE;
5926 int num_char_bytes = 0;
5929 for (i = 0; i <= max_length; i++) {
5932 } else if (i == max_length) {
5933 result |= VK_STRING_ERROR_LENGTH;
5935 } else if ((utf8[i] >= 0x20) && (utf8[i] < 0x7f)) {
5937 } else if ((utf8[i] & UTF8_ONE_BYTE_MASK) == UTF8_ONE_BYTE_CODE) {
5939 } else if ((utf8[i] & UTF8_TWO_BYTE_MASK) == UTF8_TWO_BYTE_CODE) {
5941 } else if ((utf8[i] & UTF8_THREE_BYTE_MASK) == UTF8_THREE_BYTE_CODE) {
5944 result = VK_STRING_ERROR_BAD_DATA;
5947 // Validate the following num_char_bytes of data
5948 for (j = 0; (j < num_char_bytes) && (i < max_length); j++) {
5949 if (++i == max_length) {
5950 result |= VK_STRING_ERROR_LENGTH;
5953 if ((utf8[i] & UTF8_DATA_BYTE_MASK) != UTF8_DATA_BYTE_CODE) {
5954 result |= VK_STRING_ERROR_BAD_DATA;
5961 VKAPI_ATTR VkResult VKAPI_CALL
5962 terminator_EnumerateInstanceExtensionProperties(const VkEnumerateInstanceExtensionPropertiesChain *chain, const char *pLayerName,
5963 uint32_t *pPropertyCount, VkExtensionProperties *pProperties) {
5964 struct loader_extension_list *global_ext_list = NULL;
5965 struct loader_layer_list instance_layers;
5966 struct loader_extension_list local_ext_list;
5967 struct loader_icd_tramp_list icd_tramp_list;
5969 VkResult res = VK_SUCCESS;
5971 // tls_instance = NULL;
5972 memset(&local_ext_list, 0, sizeof(local_ext_list));
5973 memset(&instance_layers, 0, sizeof(instance_layers));
5975 // Get layer libraries if needed
5976 if (pLayerName && strlen(pLayerName) != 0) {
5977 if (vk_string_validate(MaxLoaderStringLength, pLayerName) != VK_STRING_ERROR_NONE) {
5979 "vkEnumerateInstanceExtensionProperties: "
5980 "pLayerName is too long or is badly formed");
5981 res = VK_ERROR_EXTENSION_NOT_PRESENT;
5985 loader_layer_scan(NULL, &instance_layers);
5986 for (uint32_t i = 0; i < instance_layers.count; i++) {
5987 struct loader_layer_properties *props = &instance_layers.list[i];
5988 if (strcmp(props->info.layerName, pLayerName) == 0) {
5989 global_ext_list = &props->instance_extension_list;
5994 // Scan/discover all ICD libraries
5995 memset(&icd_tramp_list, 0, sizeof(icd_tramp_list));
5996 res = loader_icd_scan(NULL, &icd_tramp_list);
5997 if (VK_SUCCESS != res) {
6000 // Get extensions from all ICD's, merge so no duplicates
6001 res = loader_get_icd_loader_instance_extensions(NULL, &icd_tramp_list, &local_ext_list);
6002 if (VK_SUCCESS != res) {
6005 loader_scanned_icd_clear(NULL, &icd_tramp_list);
6007 // Append enabled implicit layers.
6008 loader_implicit_layer_scan(NULL, &instance_layers);
6009 for (uint32_t i = 0; i < instance_layers.count; i++) {
6010 if (!loader_is_implicit_layer_enabled(NULL, &instance_layers.list[i])) {
6013 struct loader_extension_list *ext_list = &instance_layers.list[i].instance_extension_list;
6014 loader_add_to_ext_list(NULL, &local_ext_list, ext_list->count, ext_list->list);
6017 global_ext_list = &local_ext_list;
6020 if (global_ext_list == NULL) {
6021 res = VK_ERROR_LAYER_NOT_PRESENT;
6025 if (pProperties == NULL) {
6026 *pPropertyCount = global_ext_list->count;
6030 copy_size = *pPropertyCount < global_ext_list->count ? *pPropertyCount : global_ext_list->count;
6031 for (uint32_t i = 0; i < copy_size; i++) {
6032 memcpy(&pProperties[i], &global_ext_list->list[i], sizeof(VkExtensionProperties));
6034 *pPropertyCount = copy_size;
6036 if (copy_size < global_ext_list->count) {
6037 res = VK_INCOMPLETE;
6043 loader_destroy_generic_list(NULL, (struct loader_generic_list *)&local_ext_list);
6044 loader_delete_layer_properties(NULL, &instance_layers);
6048 VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateInstanceLayerProperties(const VkEnumerateInstanceLayerPropertiesChain *chain,
6049 uint32_t *pPropertyCount,
6050 VkLayerProperties *pProperties) {
6051 VkResult result = VK_SUCCESS;
6052 struct loader_layer_list instance_layer_list;
6053 tls_instance = NULL;
6055 LOADER_PLATFORM_THREAD_ONCE(&once_init, loader_initialize);
6059 // Get layer libraries
6060 memset(&instance_layer_list, 0, sizeof(instance_layer_list));
6061 loader_layer_scan(NULL, &instance_layer_list);
6063 if (pProperties == NULL) {
6064 *pPropertyCount = instance_layer_list.count;
6068 copy_size = (*pPropertyCount < instance_layer_list.count) ? *pPropertyCount : instance_layer_list.count;
6069 for (uint32_t i = 0; i < copy_size; i++) {
6070 memcpy(&pProperties[i], &instance_layer_list.list[i].info, sizeof(VkLayerProperties));
6073 *pPropertyCount = copy_size;
6075 if (copy_size < instance_layer_list.count) {
6076 result = VK_INCOMPLETE;
6082 loader_delete_layer_properties(NULL, &instance_layer_list);
6086 #if defined(_WIN32) && defined(LOADER_DYNAMIC_LIB)
6087 BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, LPVOID reserved) {
6089 case DLL_PROCESS_ATTACH:
6090 loader_initialize();
6092 case DLL_PROCESS_DETACH:
6093 if (NULL == reserved) {
6103 #elif !defined(_WIN32)
6104 __attribute__((constructor)) void loader_init_library() { loader_initialize(); }
6106 __attribute__((destructor)) void loader_free_library() { loader_release(); }