xref: /third_party/vulkan-loader/loader/loader.c (revision 5db71995)
1/*
2 *
3 * Copyright (c) 2014-2023 The Khronos Group Inc.
4 * Copyright (c) 2014-2023 Valve Corporation
5 * Copyright (c) 2014-2023 LunarG, Inc.
6 * Copyright (C) 2015 Google Inc.
7 * Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
8 * Copyright (c) 2023-2023 RasterGrid Kft.
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 *     http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21
22 *
23 * Author: Jon Ashburn <jon@lunarg.com>
24 * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
25 * Author: Mark Young <marky@lunarg.com>
26 * Author: Lenny Komow <lenny@lunarg.com>
27 * Author: Charles Giessen <charles@lunarg.com>
28 *
29 */
30
31#include "loader.h"
32
33#include <ctype.h>
34#include <inttypes.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <stdarg.h>
38#include <stdbool.h>
39#include <string.h>
40#include <stddef.h>
41
42#if defined(__APPLE__)
43#include <CoreFoundation/CoreFoundation.h>
44#include <sys/param.h>
45#endif
46
47#include <sys/types.h>
48#if defined(_WIN32)
49#include "dirent_on_windows.h"
50#elif COMMON_UNIX_PLATFORMS
51#include <dirent.h>
52#else
53#warning dirent.h not available on this platform
54#endif  // _WIN32
55
56#include "allocation.h"
57#include "cJSON.h"
58#include "debug_utils.h"
59#include "loader_environment.h"
60#include "gpa_helper.h"
61#include "log.h"
62#include "unknown_function_handling.h"
63#include "vk_loader_platform.h"
64#include "wsi.h"
65
66#if defined(WIN32)
67#include "loader_windows.h"
68#endif
69#if defined(LOADER_ENABLE_LINUX_SORT)
70// This header is currently only used when sorting Linux devices, so don't include it otherwise.
71#include "loader_linux.h"
72#endif  // LOADER_ENABLE_LINUX_SORT
73
74// Generated file containing all the extension data
75#include "vk_loader_extensions.c"
76
77struct loader_struct loader = {0};
78
79struct activated_layer_info {
80    char *name;
81    char *manifest;
82    char *library;
83    bool is_implicit;
84    char *disable_env;
85};
86
87// thread safety lock for accessing global data structures such as "loader"
88// all entrypoints on the instance chain need to be locked except GPA
89// additionally CreateDevice and DestroyDevice needs to be locked
90loader_platform_thread_mutex loader_lock;
91loader_platform_thread_mutex loader_preload_icd_lock;
92loader_platform_thread_mutex loader_global_instance_list_lock;
93
94// A list of ICDs that gets initialized when the loader does its global initialization. This list should never be used by anything
95// other than EnumerateInstanceExtensionProperties(), vkDestroyInstance, and loader_release(). This list does not change
96// functionality, but the fact that the libraries already been loaded causes any call that needs to load ICD libraries to speed up
97// significantly. This can have a huge impact when making repeated calls to vkEnumerateInstanceExtensionProperties and
98// vkCreateInstance.
99struct loader_icd_tramp_list scanned_icds;
100
101// controls whether loader_platform_close_library() closes the libraries or not - controlled by an environment
102// variables - this is just the definition of the variable, usage is in vk_loader_platform.h
103bool loader_disable_dynamic_library_unloading;
104
105LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_init);
106
107// Creates loader_api_version struct that contains the major and minor fields, setting patch to 0
108loader_api_version loader_make_version(uint32_t version) {
109    loader_api_version out_version;
110    out_version.major = VK_API_VERSION_MAJOR(version);
111    out_version.minor = VK_API_VERSION_MINOR(version);
112    out_version.patch = 0;
113    return out_version;
114}
115
116// Creates loader_api_version struct containing the major, minor, and patch fields
117loader_api_version loader_make_full_version(uint32_t version) {
118    loader_api_version out_version;
119    out_version.major = VK_API_VERSION_MAJOR(version);
120    out_version.minor = VK_API_VERSION_MINOR(version);
121    out_version.patch = VK_API_VERSION_PATCH(version);
122    return out_version;
123}
124
125loader_api_version loader_combine_version(uint32_t major, uint32_t minor, uint32_t patch) {
126    loader_api_version out_version;
127    out_version.major = (uint16_t)major;
128    out_version.minor = (uint16_t)minor;
129    out_version.patch = (uint16_t)patch;
130    return out_version;
131}
132
133// Helper macros for determining if a version is valid or not
134bool loader_check_version_meets_required(loader_api_version required, loader_api_version version) {
135    // major version is satisfied
136    return (version.major > required.major) ||
137           // major version is equal, minor version is patch version is greater to minimum minor
138           (version.major == required.major && version.minor > required.minor) ||
139           // major and minor version are equal, patch version is greater or equal to minimum patch
140           (version.major == required.major && version.minor == required.minor && version.patch >= required.patch);
141}
142
143// Wrapper around opendir so that the dirent_on_windows gets the instance it needs
144// while linux opendir & readdir does not
145DIR *loader_opendir(const struct loader_instance *instance, const char *name) {
146#if defined(_WIN32)
147    return opendir(instance ? &instance->alloc_callbacks : NULL, name);
148#elif COMMON_UNIX_PLATFORMS
149    (void)instance;
150    return opendir(name);
151#else
152#warning dirent.h - opendir not available on this platform
153#endif  // _WIN32
154}
155int loader_closedir(const struct loader_instance *instance, DIR *dir) {
156#if defined(_WIN32)
157    return closedir(instance ? &instance->alloc_callbacks : NULL, dir);
158#elif COMMON_UNIX_PLATFORMS
159    (void)instance;
160    return closedir(dir);
161#else
162#warning dirent.h - closedir not available on this platform
163#endif  // _WIN32
164}
165
166bool is_json(const char *path, size_t len) {
167    if (len < 5) {
168        return false;
169    }
170    return !strncmp(path, ".json", 5);
171}
172
173// Handle error from to library loading
174void loader_handle_load_library_error(const struct loader_instance *inst, const char *filename,
175                                      enum loader_layer_library_status *lib_status) {
176    const char *error_message = loader_platform_open_library_error(filename);
177    // If the error is due to incompatible architecture (eg 32 bit vs 64 bit), report it with INFO level
178    // Discussed in Github issue 262 & 644
179    // "wrong ELF class" is a linux error, " with error 193" is a windows error
180    VkFlags err_flag = VULKAN_LOADER_ERROR_BIT;
181    if (strstr(error_message, "wrong ELF class:") != NULL || strstr(error_message, " with error 193") != NULL) {
182        err_flag = VULKAN_LOADER_INFO_BIT;
183        if (NULL != lib_status) {
184            *lib_status = LOADER_LAYER_LIB_ERROR_WRONG_BIT_TYPE;
185        }
186    }
187    // Check if the error is due to lack of memory
188    // "with error 8" is the windows error code for OOM cases, aka ERROR_NOT_ENOUGH_MEMORY
189    // Linux doesn't have such a nice error message - only if there are reported issues should this be called
190    else if (strstr(error_message, " with error 8") != NULL) {
191        if (NULL != lib_status) {
192            *lib_status = LOADER_LAYER_LIB_ERROR_OUT_OF_MEMORY;
193        }
194    } else if (NULL != lib_status) {
195        *lib_status = LOADER_LAYER_LIB_ERROR_FAILED_TO_LOAD;
196    }
197    loader_log(inst, err_flag, 0, error_message);
198}
199
200VKAPI_ATTR VkResult VKAPI_CALL vkSetInstanceDispatch(VkInstance instance, void *object) {
201    struct loader_instance *inst = loader_get_instance(instance);
202    if (!inst) {
203        loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "vkSetInstanceDispatch: Can not retrieve Instance dispatch table.");
204        return VK_ERROR_INITIALIZATION_FAILED;
205    }
206    loader_set_dispatch(object, inst->disp);
207    return VK_SUCCESS;
208}
209
210VKAPI_ATTR VkResult VKAPI_CALL vkSetDeviceDispatch(VkDevice device, void *object) {
211    struct loader_device *dev;
212    struct loader_icd_term *icd_term = loader_get_icd_and_device(device, &dev, NULL);
213
214    if (NULL == icd_term || NULL == dev) {
215        return VK_ERROR_INITIALIZATION_FAILED;
216    }
217    loader_set_dispatch(object, &dev->loader_dispatch);
218    return VK_SUCCESS;
219}
220
221void loader_free_layer_properties(const struct loader_instance *inst, struct loader_layer_properties *layer_properties) {
222    loader_instance_heap_free(inst, layer_properties->manifest_file_name);
223    loader_instance_heap_free(inst, layer_properties->lib_name);
224    loader_instance_heap_free(inst, layer_properties->functions.str_gipa);
225    loader_instance_heap_free(inst, layer_properties->functions.str_gdpa);
226    loader_instance_heap_free(inst, layer_properties->functions.str_negotiate_interface);
227    loader_destroy_generic_list(inst, (struct loader_generic_list *)&layer_properties->instance_extension_list);
228    if (layer_properties->device_extension_list.capacity > 0 && NULL != layer_properties->device_extension_list.list) {
229        for (uint32_t i = 0; i < layer_properties->device_extension_list.count; i++) {
230            free_string_list(inst, &layer_properties->device_extension_list.list[i].entrypoints);
231        }
232    }
233    loader_destroy_generic_list(inst, (struct loader_generic_list *)&layer_properties->device_extension_list);
234    loader_instance_heap_free(inst, layer_properties->disable_env_var.name);
235    loader_instance_heap_free(inst, layer_properties->disable_env_var.value);
236    loader_instance_heap_free(inst, layer_properties->enable_env_var.name);
237    loader_instance_heap_free(inst, layer_properties->enable_env_var.value);
238    free_string_list(inst, &layer_properties->component_layer_names);
239    loader_instance_heap_free(inst, layer_properties->pre_instance_functions.enumerate_instance_extension_properties);
240    loader_instance_heap_free(inst, layer_properties->pre_instance_functions.enumerate_instance_layer_properties);
241    loader_instance_heap_free(inst, layer_properties->pre_instance_functions.enumerate_instance_version);
242    free_string_list(inst, &layer_properties->override_paths);
243    free_string_list(inst, &layer_properties->blacklist_layer_names);
244    free_string_list(inst, &layer_properties->app_key_paths);
245
246    // Make sure to clear out the removed layer, in case new layers are added in the previous location
247    memset(layer_properties, 0, sizeof(struct loader_layer_properties));
248}
249
250VkResult loader_init_library_list(struct loader_layer_list *instance_layers, loader_platform_dl_handle **libs) {
251    if (instance_layers->count > 0) {
252        *libs = loader_calloc(NULL, sizeof(loader_platform_dl_handle) * instance_layers->count, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
253        if (*libs == NULL) {
254            return VK_ERROR_OUT_OF_HOST_MEMORY;
255        }
256    }
257    return VK_SUCCESS;
258}
259
260VkResult loader_copy_to_new_str(const struct loader_instance *inst, const char *source_str, char **dest_str) {
261    assert(source_str && dest_str);
262    size_t str_len = strlen(source_str) + 1;
263    *dest_str = loader_instance_heap_calloc(inst, str_len, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
264    if (NULL == *dest_str) return VK_ERROR_OUT_OF_HOST_MEMORY;
265    loader_strncpy(*dest_str, str_len, source_str, str_len);
266    (*dest_str)[str_len - 1] = 0;
267    return VK_SUCCESS;
268}
269
270VkResult create_string_list(const struct loader_instance *inst, uint32_t allocated_count, struct loader_string_list *string_list) {
271    assert(string_list);
272    string_list->list = loader_instance_heap_calloc(inst, sizeof(char *) * allocated_count, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
273    if (NULL == string_list->list) {
274        return VK_ERROR_OUT_OF_HOST_MEMORY;
275    }
276    string_list->allocated_count = allocated_count;
277    string_list->count = 0;
278    return VK_SUCCESS;
279}
280
281VkResult append_str_to_string_list(const struct loader_instance *inst, struct loader_string_list *string_list, char *str) {
282    assert(string_list && str);
283    if (string_list->allocated_count == 0) {
284        string_list->allocated_count = 32;
285        string_list->list =
286            loader_instance_heap_calloc(inst, sizeof(char *) * string_list->allocated_count, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
287        if (NULL == string_list->list) {
288            return VK_ERROR_OUT_OF_HOST_MEMORY;
289        }
290    } else if (string_list->count + 1 > string_list->allocated_count) {
291        uint32_t new_allocated_count = string_list->allocated_count * 2;
292        string_list->list = loader_instance_heap_realloc(inst, string_list->list, sizeof(char *) * string_list->allocated_count,
293                                                         sizeof(char *) * new_allocated_count, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
294        if (NULL == string_list->list) {
295            return VK_ERROR_OUT_OF_HOST_MEMORY;
296        }
297        // Null out the new space
298        memset(string_list->list + string_list->allocated_count, 0, string_list->allocated_count);
299        string_list->allocated_count *= 2;
300    }
301    string_list->list[string_list->count++] = str;
302    return VK_SUCCESS;
303}
304
305VkResult copy_str_to_string_list(const struct loader_instance *inst, struct loader_string_list *string_list, const char *str,
306                                 size_t str_len) {
307    assert(string_list && str);
308    char *new_str = loader_instance_heap_calloc(inst, sizeof(char *) * str_len + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
309    if (NULL == new_str) {
310        return VK_ERROR_OUT_OF_HOST_MEMORY;
311    }
312    loader_strncpy(new_str, sizeof(char *) * str_len + 1, str, str_len);
313    new_str[str_len] = '\0';
314    VkResult res = append_str_to_string_list(inst, string_list, new_str);
315    if (res != VK_SUCCESS) {
316        // Cleanup new_str if the append failed - as append_str_to_string_list takes ownership but not if the function fails
317        loader_instance_heap_free(inst, new_str);
318    }
319    return res;
320}
321
322void free_string_list(const struct loader_instance *inst, struct loader_string_list *string_list) {
323    assert(string_list);
324    if (string_list->list) {
325        for (uint32_t i = 0; i < string_list->count; i++) {
326            loader_instance_heap_free(inst, string_list->list[i]);
327            string_list->list[i] = NULL;
328        }
329        loader_instance_heap_free(inst, string_list->list);
330    }
331    memset(string_list, 0, sizeof(struct loader_string_list));
332}
333
334// Given string of three part form "maj.min.pat" convert to a vulkan version number.
335// Also can understand four part form "variant.major.minor.patch" if provided.
336uint32_t loader_parse_version_string(char *vers_str) {
337    uint32_t variant = 0, major = 0, minor = 0, patch = 0;
338    char *vers_tok;
339    char *context = NULL;
340    if (!vers_str) {
341        return 0;
342    }
343
344    vers_tok = thread_safe_strtok(vers_str, ".\"\n\r", &context);
345    if (NULL != vers_tok) {
346        major = (uint16_t)atoi(vers_tok);
347        vers_tok = thread_safe_strtok(NULL, ".\"\n\r", &context);
348        if (NULL != vers_tok) {
349            minor = (uint16_t)atoi(vers_tok);
350            vers_tok = thread_safe_strtok(NULL, ".\"\n\r", &context);
351            if (NULL != vers_tok) {
352                patch = (uint16_t)atoi(vers_tok);
353                vers_tok = thread_safe_strtok(NULL, ".\"\n\r", &context);
354                // check that we are using a 4 part version string
355                if (NULL != vers_tok) {
356                    // if we are, move the values over into the correct place
357                    variant = major;
358                    major = minor;
359                    minor = patch;
360                    patch = (uint16_t)atoi(vers_tok);
361                }
362            }
363        }
364    }
365
366    return VK_MAKE_API_VERSION(variant, major, minor, patch);
367}
368
369bool compare_vk_extension_properties(const VkExtensionProperties *op1, const VkExtensionProperties *op2) {
370    return strcmp(op1->extensionName, op2->extensionName) == 0 ? true : false;
371}
372
373// Search the given ext_array for an extension matching the given vk_ext_prop
374bool has_vk_extension_property_array(const VkExtensionProperties *vk_ext_prop, const uint32_t count,
375                                     const VkExtensionProperties *ext_array) {
376    for (uint32_t i = 0; i < count; i++) {
377        if (compare_vk_extension_properties(vk_ext_prop, &ext_array[i])) return true;
378    }
379    return false;
380}
381
382// Search the given ext_list for an extension matching the given vk_ext_prop
383bool has_vk_extension_property(const VkExtensionProperties *vk_ext_prop, const struct loader_extension_list *ext_list) {
384    for (uint32_t i = 0; i < ext_list->count; i++) {
385        if (compare_vk_extension_properties(&ext_list->list[i], vk_ext_prop)) return true;
386    }
387    return false;
388}
389
390// Search the given ext_list for a device extension matching the given ext_prop
391bool has_vk_dev_ext_property(const VkExtensionProperties *ext_prop, const struct loader_device_extension_list *ext_list) {
392    for (uint32_t i = 0; i < ext_list->count; i++) {
393        if (compare_vk_extension_properties(&ext_list->list[i].props, ext_prop)) return true;
394    }
395    return false;
396}
397
398VkResult loader_append_layer_property(const struct loader_instance *inst, struct loader_layer_list *layer_list,
399                                      struct loader_layer_properties *layer_property) {
400    VkResult res = VK_SUCCESS;
401    if (layer_list->capacity == 0) {
402        res = loader_init_generic_list(inst, (struct loader_generic_list *)layer_list, sizeof(struct loader_layer_properties));
403        if (VK_SUCCESS != res) {
404            goto out;
405        }
406    }
407
408    // Ensure enough room to add an entry
409    if ((layer_list->count + 1) * sizeof(struct loader_layer_properties) > layer_list->capacity) {
410        void *new_ptr = loader_instance_heap_realloc(inst, layer_list->list, layer_list->capacity, layer_list->capacity * 2,
411                                                     VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
412        if (NULL == new_ptr) {
413            loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_append_layer_property: realloc failed for layer list");
414            res = VK_ERROR_OUT_OF_HOST_MEMORY;
415            goto out;
416        }
417        layer_list->list = new_ptr;
418        memset((uint8_t *)layer_list->list + layer_list->capacity, 0, layer_list->capacity);
419        layer_list->capacity *= 2;
420    }
421    memcpy(&layer_list->list[layer_list->count], layer_property, sizeof(struct loader_layer_properties));
422    layer_list->count++;
423    memset(layer_property, 0, sizeof(struct loader_layer_properties));
424out:
425    if (res != VK_SUCCESS) {
426        loader_free_layer_properties(inst, layer_property);
427    }
428    return res;
429}
430
431// Search the given layer list for a layer property matching the given layer name
432struct loader_layer_properties *loader_find_layer_property(const char *name, const struct loader_layer_list *layer_list) {
433    for (uint32_t i = 0; i < layer_list->count; i++) {
434        const VkLayerProperties *item = &layer_list->list[i].info;
435        if (strcmp(name, item->layerName) == 0) return &layer_list->list[i];
436    }
437    return NULL;
438}
439
440struct loader_layer_properties *loader_find_pointer_layer_property(const char *name,
441                                                                   const struct loader_pointer_layer_list *layer_list) {
442    for (uint32_t i = 0; i < layer_list->count; i++) {
443        const VkLayerProperties *item = &layer_list->list[i]->info;
444        if (strcmp(name, item->layerName) == 0) return layer_list->list[i];
445    }
446    return NULL;
447}
448
449// Search the given layer list for a layer matching the given layer name
450bool loader_find_layer_name_in_list(const char *name, const struct loader_pointer_layer_list *layer_list) {
451    if (NULL == layer_list) {
452        return false;
453    }
454    if (NULL != loader_find_pointer_layer_property(name, layer_list)) {
455        return true;
456    }
457    return false;
458}
459
460// Search the given meta-layer's component list for a layer matching the given layer name
461bool loader_find_layer_name_in_meta_layer(const struct loader_instance *inst, const char *layer_name,
462                                          struct loader_layer_list *layer_list, struct loader_layer_properties *meta_layer_props) {
463    for (uint32_t comp_layer = 0; comp_layer < meta_layer_props->component_layer_names.count; comp_layer++) {
464        if (!strcmp(meta_layer_props->component_layer_names.list[comp_layer], layer_name)) {
465            return true;
466        }
467        struct loader_layer_properties *comp_layer_props =
468            loader_find_layer_property(meta_layer_props->component_layer_names.list[comp_layer], layer_list);
469        if (comp_layer_props->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER) {
470            return loader_find_layer_name_in_meta_layer(inst, layer_name, layer_list, comp_layer_props);
471        }
472    }
473    return false;
474}
475
476// Search the override layer's blacklist for a layer matching the given layer name
477bool loader_find_layer_name_in_blacklist(const char *layer_name, struct loader_layer_properties *meta_layer_props) {
478    for (uint32_t black_layer = 0; black_layer < meta_layer_props->blacklist_layer_names.count; ++black_layer) {
479        if (!strcmp(meta_layer_props->blacklist_layer_names.list[black_layer], layer_name)) {
480            return true;
481        }
482    }
483    return false;
484}
485
486// Remove all layer properties entries from the list
487void loader_delete_layer_list_and_properties(const struct loader_instance *inst, struct loader_layer_list *layer_list) {
488    uint32_t i;
489    if (!layer_list) return;
490
491    for (i = 0; i < layer_list->count; i++) {
492        if (layer_list->list[i].lib_handle) {
493            loader_platform_close_library(layer_list->list[i].lib_handle);
494            loader_log(inst, VULKAN_LOADER_DEBUG_BIT | VULKAN_LOADER_LAYER_BIT, 0, "Unloading layer library %s",
495                       layer_list->list[i].lib_name);
496            layer_list->list[i].lib_handle = NULL;
497        }
498        loader_free_layer_properties(inst, &(layer_list->list[i]));
499    }
500    layer_list->count = 0;
501
502    if (layer_list->capacity > 0) {
503        layer_list->capacity = 0;
504        loader_instance_heap_free(inst, layer_list->list);
505    }
506    memset(layer_list, 0, sizeof(struct loader_layer_list));
507}
508
509void loader_remove_layer_in_list(const struct loader_instance *inst, struct loader_layer_list *layer_list,
510                                 uint32_t layer_to_remove) {
511    if (layer_list == NULL || layer_to_remove >= layer_list->count) {
512        return;
513    }
514    loader_free_layer_properties(inst, &(layer_list->list[layer_to_remove]));
515
516    // Remove the current invalid meta-layer from the layer list.  Use memmove since we are
517    // overlapping the source and destination addresses.
518    memmove(&layer_list->list[layer_to_remove], &layer_list->list[layer_to_remove + 1],
519            sizeof(struct loader_layer_properties) * (layer_list->count - 1 - layer_to_remove));
520
521    // Decrement the count (because we now have one less) and decrement the loop index since we need to
522    // re-check this index.
523    layer_list->count--;
524}
525
526// Remove all layers in the layer list that are blacklisted by the override layer.
527// NOTE: This should only be called if an override layer is found and not expired.
528void loader_remove_layers_in_blacklist(const struct loader_instance *inst, struct loader_layer_list *layer_list) {
529    struct loader_layer_properties *override_prop = loader_find_layer_property(VK_OVERRIDE_LAYER_NAME, layer_list);
530    if (NULL == override_prop) {
531        return;
532    }
533
534    for (int32_t j = 0; j < (int32_t)(layer_list->count); j++) {
535        struct loader_layer_properties cur_layer_prop = layer_list->list[j];
536        const char *cur_layer_name = &cur_layer_prop.info.layerName[0];
537
538        // Skip the override layer itself.
539        if (!strcmp(VK_OVERRIDE_LAYER_NAME, cur_layer_name)) {
540            continue;
541        }
542
543        // If found in the override layer's blacklist, remove it
544        if (loader_find_layer_name_in_blacklist(cur_layer_name, override_prop)) {
545            loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0,
546                       "loader_remove_layers_in_blacklist: Override layer is active and layer %s is in the blacklist inside of it. "
547                       "Removing that layer from current layer list.",
548                       cur_layer_name);
549            loader_remove_layer_in_list(inst, layer_list, j);
550            j--;
551
552            // Re-do the query for the override layer
553            override_prop = loader_find_layer_property(VK_OVERRIDE_LAYER_NAME, layer_list);
554        }
555    }
556}
557
558// Remove all layers in the layer list that are not found inside any implicit meta-layers.
559void loader_remove_layers_not_in_implicit_meta_layers(const struct loader_instance *inst, struct loader_layer_list *layer_list) {
560    int32_t i;
561    int32_t j;
562    int32_t layer_count = (int32_t)(layer_list->count);
563
564    for (i = 0; i < layer_count; i++) {
565        layer_list->list[i].keep = false;
566    }
567
568    for (i = 0; i < layer_count; i++) {
569        struct loader_layer_properties *cur_layer_prop = &layer_list->list[i];
570
571        if (0 == (cur_layer_prop->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER)) {
572            cur_layer_prop->keep = true;
573            continue;
574        }
575        for (j = 0; j < layer_count; j++) {
576            struct loader_layer_properties *layer_to_check = &layer_list->list[j];
577
578            if (i == j) {
579                continue;
580            }
581
582            if (layer_to_check->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER) {
583                // For all layers found in this meta layer, we want to keep them as well.
584                if (loader_find_layer_name_in_meta_layer(inst, cur_layer_prop->info.layerName, layer_list, layer_to_check)) {
585                    cur_layer_prop->keep = true;
586                }
587            }
588        }
589    }
590
591    // Remove any layers we don't want to keep (Don't use layer_count here as we need it to be
592    // dynamically updated if we delete a layer property in the list).
593    for (i = 0; i < (int32_t)(layer_list->count); i++) {
594        struct loader_layer_properties *cur_layer_prop = &layer_list->list[i];
595        if (!cur_layer_prop->keep) {
596            loader_log(
597                inst, VULKAN_LOADER_DEBUG_BIT, 0,
598                "loader_remove_layers_not_in_implicit_meta_layers : Implicit meta-layers are active, and layer %s is not list "
599                "inside of any.  So removing layer from current layer list.",
600                cur_layer_prop->info.layerName);
601            loader_remove_layer_in_list(inst, layer_list, i);
602            i--;
603        }
604    }
605}
606
607VkResult loader_add_instance_extensions(const struct loader_instance *inst,
608                                        const PFN_vkEnumerateInstanceExtensionProperties fp_get_props, const char *lib_name,
609                                        struct loader_extension_list *ext_list) {
610    uint32_t i, count = 0;
611    VkExtensionProperties *ext_props;
612    VkResult res = VK_SUCCESS;
613
614    if (!fp_get_props) {
615        // No EnumerateInstanceExtensionProperties defined
616        goto out;
617    }
618
619    // Make sure we never call ourself by accident, this should never happen outside of error paths
620    if (fp_get_props == vkEnumerateInstanceExtensionProperties) {
621        loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
622                   "loader_add_instance_extensions: %s's vkEnumerateInstanceExtensionProperties points to the loader, this would "
623                   "lead to infinite recursion.",
624                   lib_name);
625        goto out;
626    }
627
628    res = fp_get_props(NULL, &count, NULL);
629    if (res != VK_SUCCESS) {
630        loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
631                   "loader_add_instance_extensions: Error getting Instance extension count from %s", lib_name);
632        goto out;
633    }
634
635    if (count == 0) {
636        // No ExtensionProperties to report
637        goto out;
638    }
639
640    ext_props = loader_stack_alloc(count * sizeof(VkExtensionProperties));
641    if (NULL == ext_props) {
642        res = VK_ERROR_OUT_OF_HOST_MEMORY;
643        goto out;
644    }
645
646    res = fp_get_props(NULL, &count, ext_props);
647    if (res != VK_SUCCESS) {
648        loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_add_instance_extensions: Error getting Instance extensions from %s",
649                   lib_name);
650        goto out;
651    }
652
653    for (i = 0; i < count; i++) {
654        bool ext_unsupported = wsi_unsupported_instance_extension(&ext_props[i]);
655        if (!ext_unsupported) {
656            res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
657            if (res != VK_SUCCESS) {
658                goto out;
659            }
660        }
661    }
662
663out:
664    return res;
665}
666
667VkResult loader_add_device_extensions(const struct loader_instance *inst,
668                                      PFN_vkEnumerateDeviceExtensionProperties fpEnumerateDeviceExtensionProperties,
669                                      VkPhysicalDevice physical_device, const char *lib_name,
670                                      struct loader_extension_list *ext_list) {
671    uint32_t i = 0, count = 0;
672    VkResult res = VK_SUCCESS;
673    VkExtensionProperties *ext_props = NULL;
674
675    res = fpEnumerateDeviceExtensionProperties(physical_device, NULL, &count, NULL);
676    if (res != VK_SUCCESS) {
677        loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
678                   "loader_add_device_extensions: Error getting physical device extension info count from library %s", lib_name);
679        return res;
680    }
681    if (count > 0) {
682        ext_props = loader_stack_alloc(count * sizeof(VkExtensionProperties));
683        if (!ext_props) {
684            loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
685                       "loader_add_device_extensions: Failed to allocate space for device extension properties from library %s.",
686                       lib_name);
687            return VK_ERROR_OUT_OF_HOST_MEMORY;
688        }
689        res = fpEnumerateDeviceExtensionProperties(physical_device, NULL, &count, ext_props);
690        if (res != VK_SUCCESS) {
691            return res;
692        }
693        for (i = 0; i < count; i++) {
694            res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
695            if (res != VK_SUCCESS) {
696                return res;
697            }
698        }
699    }
700
701    return VK_SUCCESS;
702}
703
704VkResult loader_init_generic_list(const struct loader_instance *inst, struct loader_generic_list *list_info, size_t element_size) {
705    size_t capacity = 32 * element_size;
706    list_info->count = 0;
707    list_info->capacity = 0;
708    list_info->list = loader_instance_heap_calloc(inst, capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
709    if (list_info->list == NULL) {
710        loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_init_generic_list: Failed to allocate space for generic list");
711        return VK_ERROR_OUT_OF_HOST_MEMORY;
712    }
713    list_info->capacity = capacity;
714    return VK_SUCCESS;
715}
716
717void loader_destroy_generic_list(const struct loader_instance *inst, struct loader_generic_list *list) {
718    loader_instance_heap_free(inst, list->list);
719    memset(list, 0, sizeof(struct loader_generic_list));
720}
721
722// Append non-duplicate extension properties defined in props to the given ext_list.
723// Return - Vk_SUCCESS on success
724VkResult loader_add_to_ext_list(const struct loader_instance *inst, struct loader_extension_list *ext_list,
725                                uint32_t prop_list_count, const VkExtensionProperties *props) {
726    if (ext_list->list == NULL || ext_list->capacity == 0) {
727        VkResult res = loader_init_generic_list(inst, (struct loader_generic_list *)ext_list, sizeof(VkExtensionProperties));
728        if (VK_SUCCESS != res) {
729            return res;
730        }
731    }
732
733    for (uint32_t i = 0; i < prop_list_count; i++) {
734        const VkExtensionProperties *cur_ext = &props[i];
735
736        // look for duplicates
737        if (has_vk_extension_property(cur_ext, ext_list)) {
738            continue;
739        }
740
741        // add to list at end
742        // check for enough capacity
743        if (ext_list->count * sizeof(VkExtensionProperties) >= ext_list->capacity) {
744            void *new_ptr = loader_instance_heap_realloc(inst, ext_list->list, ext_list->capacity, ext_list->capacity * 2,
745                                                         VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
746            if (new_ptr == NULL) {
747                loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
748                           "loader_add_to_ext_list: Failed to reallocate space for extension list");
749                return VK_ERROR_OUT_OF_HOST_MEMORY;
750            }
751            ext_list->list = new_ptr;
752
753            // double capacity
754            ext_list->capacity *= 2;
755        }
756
757        memcpy(&ext_list->list[ext_list->count], cur_ext, sizeof(VkExtensionProperties));
758        ext_list->count++;
759    }
760    return VK_SUCCESS;
761}
762
763// Append one extension property defined in props with entrypoints defined in entries to the given
764// ext_list. Do not append if a duplicate.
765// If this is a duplicate, this function free's the passed in entries - as in it takes ownership over that list (if it is not
766// NULL) Return - Vk_SUCCESS on success
767VkResult loader_add_to_dev_ext_list(const struct loader_instance *inst, struct loader_device_extension_list *ext_list,
768                                    const VkExtensionProperties *props, struct loader_string_list *entrys) {
769    VkResult res = VK_SUCCESS;
770    bool should_free_entrys = true;
771    if (ext_list->list == NULL || ext_list->capacity == 0) {
772        res = loader_init_generic_list(inst, (struct loader_generic_list *)ext_list, sizeof(struct loader_dev_ext_props));
773        if (VK_SUCCESS != res) {
774            goto out;
775        }
776    }
777
778    // look for duplicates
779    if (has_vk_dev_ext_property(props, ext_list)) {
780        goto out;
781    }
782
783    uint32_t idx = ext_list->count;
784    // add to list at end
785    // check for enough capacity
786    if (idx * sizeof(struct loader_dev_ext_props) >= ext_list->capacity) {
787        void *new_ptr = loader_instance_heap_realloc(inst, ext_list->list, ext_list->capacity, ext_list->capacity * 2,
788                                                     VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
789
790        if (NULL == new_ptr) {
791            loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
792                       "loader_add_to_dev_ext_list: Failed to reallocate space for device extension list");
793            res = VK_ERROR_OUT_OF_HOST_MEMORY;
794            goto out;
795        }
796        ext_list->list = new_ptr;
797
798        // double capacity
799        ext_list->capacity *= 2;
800    }
801
802    memcpy(&ext_list->list[idx].props, props, sizeof(*props));
803    if (entrys) {
804        ext_list->list[idx].entrypoints = *entrys;
805        should_free_entrys = false;
806    }
807    ext_list->count++;
808out:
809    if (NULL != entrys && should_free_entrys) {
810        free_string_list(inst, entrys);
811    }
812    return res;
813}
814
815// Create storage for pointers to loader_layer_properties
816bool loader_init_pointer_layer_list(const struct loader_instance *inst, struct loader_pointer_layer_list *list) {
817    list->capacity = 32 * sizeof(void *);
818    list->list = loader_instance_heap_calloc(inst, list->capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
819    if (list->list == NULL) {
820        return false;
821    }
822    list->count = 0;
823    return true;
824}
825
826// Search the given array of layer names for an entry matching the given VkLayerProperties
827bool loader_names_array_has_layer_property(const VkLayerProperties *vk_layer_prop, uint32_t layer_info_count,
828                                           struct activated_layer_info *layer_info) {
829    for (uint32_t i = 0; i < layer_info_count; i++) {
830        if (strcmp(vk_layer_prop->layerName, layer_info[i].name) == 0) {
831            return true;
832        }
833    }
834    return false;
835}
836
837void loader_destroy_pointer_layer_list(const struct loader_instance *inst, struct loader_pointer_layer_list *layer_list) {
838    loader_instance_heap_free(inst, layer_list->list);
839    memset(layer_list, 0, sizeof(struct loader_pointer_layer_list));
840}
841
842// Append layer properties defined in prop_list to the given layer_info list
843VkResult loader_add_layer_properties_to_list(const struct loader_instance *inst, struct loader_pointer_layer_list *list,
844                                             struct loader_layer_properties *props) {
845    if (list->list == NULL || list->capacity == 0) {
846        if (!loader_init_pointer_layer_list(inst, list)) {
847            return VK_ERROR_OUT_OF_HOST_MEMORY;
848        }
849    }
850
851    // Check for enough capacity
852    if (((list->count + 1) * sizeof(struct loader_layer_properties)) >= list->capacity) {
853        size_t new_capacity = list->capacity * 2;
854        void *new_ptr =
855            loader_instance_heap_realloc(inst, list->list, list->capacity, new_capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
856        if (NULL == new_ptr) {
857            loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
858                       "loader_add_layer_properties_to_list: Realloc failed for when attempting to add new layer");
859            return VK_ERROR_OUT_OF_HOST_MEMORY;
860        }
861        list->list = new_ptr;
862        list->capacity = new_capacity;
863    }
864    list->list[list->count++] = props;
865
866    return VK_SUCCESS;
867}
868
869// Determine if the provided explicit layer should be available by querying the appropriate environmental variables.
870bool loader_layer_is_available(const struct loader_instance *inst, const struct loader_envvar_all_filters *filters,
871                               const struct loader_layer_properties *prop) {
872    bool available = true;
873    bool is_implicit = (0 == (prop->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER));
874    bool disabled_by_type =
875        (is_implicit) ? (filters->disable_filter.disable_all_implicit) : (filters->disable_filter.disable_all_explicit);
876    if ((filters->disable_filter.disable_all || disabled_by_type ||
877         check_name_matches_filter_environment_var(prop->info.layerName, &filters->disable_filter.additional_filters)) &&
878        !check_name_matches_filter_environment_var(prop->info.layerName, &filters->allow_filter)) {
879        available = false;
880    }
881    if (check_name_matches_filter_environment_var(prop->info.layerName, &filters->enable_filter)) {
882        available = true;
883    } else if (!available) {
884        loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
885                   "Layer \"%s\" forced disabled because name matches filter of env var \'%s\'.", prop->info.layerName,
886                   VK_LAYERS_DISABLE_ENV_VAR);
887    }
888
889    return available;
890}
891
892// Search the given search_list for any layers in the props list.  Add these to the
893// output layer_list.
894VkResult loader_add_layer_names_to_list(const struct loader_instance *inst, const struct loader_envvar_all_filters *filters,
895                                        struct loader_pointer_layer_list *output_list,
896                                        struct loader_pointer_layer_list *expanded_output_list, uint32_t name_count,
897                                        const char *const *names, const struct loader_layer_list *source_list) {
898    VkResult err = VK_SUCCESS;
899
900    for (uint32_t i = 0; i < name_count; i++) {
901        const char *source_name = names[i];
902
903        struct loader_layer_properties *layer_prop = loader_find_layer_property(source_name, source_list);
904        if (NULL == layer_prop) {
905            loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_LAYER_BIT, 0,
906                       "loader_add_layer_names_to_list: Unable to find layer \"%s\"", source_name);
907            err = VK_ERROR_LAYER_NOT_PRESENT;
908            continue;
909        }
910
911        // Make sure the layer isn't already in the output_list, skip adding it if it is.
912        if (loader_find_layer_name_in_list(source_name, output_list)) {
913            continue;
914        }
915
916        if (!loader_layer_is_available(inst, filters, layer_prop)) {
917            continue;
918        }
919
920        // If not a meta-layer, simply add it.
921        if (0 == (layer_prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) {
922            err = loader_add_layer_properties_to_list(inst, output_list, layer_prop);
923            if (err == VK_ERROR_OUT_OF_HOST_MEMORY) return err;
924            err = loader_add_layer_properties_to_list(inst, expanded_output_list, layer_prop);
925            if (err == VK_ERROR_OUT_OF_HOST_MEMORY) return err;
926        } else {
927            err = loader_add_meta_layer(inst, filters, layer_prop, output_list, expanded_output_list, source_list, NULL);
928            if (err == VK_ERROR_OUT_OF_HOST_MEMORY) return err;
929        }
930    }
931
932    return err;
933}
934
935// Determine if the provided implicit layer should be enabled by querying the appropriate environmental variables.
936// For an implicit layer, at least a disable environment variable is required.
937bool loader_implicit_layer_is_enabled(const struct loader_instance *inst, const struct loader_envvar_all_filters *filters,
938                                      const struct loader_layer_properties *prop) {
939    bool enable = false;
940    bool forced_disabled = false;
941    bool forced_enabled = false;
942
943    if ((filters->disable_filter.disable_all || filters->disable_filter.disable_all_implicit ||
944         check_name_matches_filter_environment_var(prop->info.layerName, &filters->disable_filter.additional_filters)) &&
945        !check_name_matches_filter_environment_var(prop->info.layerName, &filters->allow_filter)) {
946        forced_disabled = true;
947    }
948    if (check_name_matches_filter_environment_var(prop->info.layerName, &filters->enable_filter)) {
949        forced_enabled = true;
950    }
951
952    // If no enable_environment variable is specified, this implicit layer is always be enabled by default.
953    if (NULL == prop->enable_env_var.name) {
954        enable = true;
955    } else {
956        char *env_value = loader_getenv(prop->enable_env_var.name, inst);
957        if (env_value && !strcmp(prop->enable_env_var.value, env_value)) {
958            enable = true;
959        }
960
961        // Otherwise, only enable this layer if the enable environment variable is defined
962        loader_free_getenv(env_value, inst);
963    }
964
965    if (forced_enabled) {
966        // Only report a message that we've forced on a layer if it wouldn't have been enabled
967        // normally.
968        if (!enable) {
969            enable = true;
970            loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
971                       "Implicit layer \"%s\" forced enabled due to env var \'%s\'.", prop->info.layerName,
972                       VK_LAYERS_ENABLE_ENV_VAR);
973        }
974    } else if (enable && forced_disabled) {
975        enable = false;
976        // Report a message that we've forced off a layer if it would have been enabled normally.
977        loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
978                   "Implicit layer \"%s\" forced disabled because name matches filter of env var \'%s\'.", prop->info.layerName,
979                   VK_LAYERS_DISABLE_ENV_VAR);
980        return enable;
981    }
982
983    // The disable_environment has priority over everything else.  If it is defined, the layer is always
984    // disabled.
985    if (NULL != prop->disable_env_var.name) {
986        char *env_value = loader_getenv(prop->disable_env_var.name, inst);
987        if (NULL != env_value) {
988            enable = false;
989        }
990        loader_free_getenv(env_value, inst);
991    } else if ((prop->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER) == 0) {
992        loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
993                   "Implicit layer \"%s\" missing disabled environment variable!", prop->info.layerName, VK_LAYERS_DISABLE_ENV_VAR);
994    }
995
996    // Enable this layer if it is included in the override layer
997    if (inst != NULL && inst->override_layer_present) {
998        struct loader_layer_properties *override = NULL;
999        for (uint32_t i = 0; i < inst->instance_layer_list.count; ++i) {
1000            if (strcmp(inst->instance_layer_list.list[i].info.layerName, VK_OVERRIDE_LAYER_NAME) == 0) {
1001                override = &inst->instance_layer_list.list[i];
1002                break;
1003            }
1004        }
1005        if (override != NULL) {
1006            for (uint32_t i = 0; i < override->component_layer_names.count; ++i) {
1007                if (strcmp(override->component_layer_names.list[i], prop->info.layerName) == 0) {
1008                    enable = true;
1009                    break;
1010                }
1011            }
1012        }
1013    }
1014
1015    return enable;
1016}
1017
1018// Check the individual implicit layer for the enable/disable environment variable settings.  Only add it after
1019// every check has passed indicating it should be used, including making sure a layer of the same name hasn't already been
1020// added.
1021VkResult loader_add_implicit_layer(const struct loader_instance *inst, struct loader_layer_properties *prop,
1022                                   const struct loader_envvar_all_filters *filters, struct loader_pointer_layer_list *target_list,
1023                                   struct loader_pointer_layer_list *expanded_target_list,
1024                                   const struct loader_layer_list *source_list) {
1025    VkResult result = VK_SUCCESS;
1026    if (loader_implicit_layer_is_enabled(inst, filters, prop)) {
1027        if (0 == (prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) {
1028            // Make sure the layer isn't already in the output_list, skip adding it if it is.
1029            if (loader_find_layer_name_in_list(&prop->info.layerName[0], target_list)) {
1030                return result;
1031            }
1032
1033            result = loader_add_layer_properties_to_list(inst, target_list, prop);
1034            if (result == VK_ERROR_OUT_OF_HOST_MEMORY) return result;
1035            if (NULL != expanded_target_list) {
1036                result = loader_add_layer_properties_to_list(inst, expanded_target_list, prop);
1037            }
1038        } else {
1039            result = loader_add_meta_layer(inst, filters, prop, target_list, expanded_target_list, source_list, NULL);
1040        }
1041    }
1042    return result;
1043}
1044
1045// Add the component layers of a meta-layer to the active list of layers
1046VkResult loader_add_meta_layer(const struct loader_instance *inst, const struct loader_envvar_all_filters *filters,
1047                               struct loader_layer_properties *prop, struct loader_pointer_layer_list *target_list,
1048                               struct loader_pointer_layer_list *expanded_target_list, const struct loader_layer_list *source_list,
1049                               bool *out_found_all_component_layers) {
1050    VkResult result = VK_SUCCESS;
1051    bool found_all_component_layers = true;
1052
1053    // We need to add all the individual component layers
1054    loader_api_version meta_layer_api_version = loader_make_version(prop->info.specVersion);
1055    for (uint32_t comp_layer = 0; comp_layer < prop->component_layer_names.count; comp_layer++) {
1056        struct loader_layer_properties *search_prop =
1057            loader_find_layer_property(prop->component_layer_names.list[comp_layer], source_list);
1058        if (search_prop != NULL) {
1059            loader_api_version search_prop_version = loader_make_version(prop->info.specVersion);
1060            if (!loader_check_version_meets_required(meta_layer_api_version, search_prop_version)) {
1061                loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
1062                           "Meta-layer \"%s\" API version %u.%u, component layer \"%s\" version %u.%u, may have "
1063                           "incompatibilities (Policy #LLP_LAYER_8)!",
1064                           prop->info.layerName, meta_layer_api_version.major, meta_layer_api_version.minor,
1065                           search_prop->info.layerName, search_prop_version.major, search_prop_version.minor);
1066            }
1067
1068            if (!loader_layer_is_available(inst, filters, search_prop)) {
1069                loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
1070                           "Meta Layer \"%s\" component layer \"%s\" disabled.", prop->info.layerName, search_prop->info.layerName);
1071                continue;
1072            }
1073
1074            // If the component layer is itself an implicit layer, we need to do the implicit layer enable
1075            // checks
1076            if (0 == (search_prop->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER)) {
1077                result = loader_add_implicit_layer(inst, search_prop, filters, target_list, expanded_target_list, source_list);
1078                if (result == VK_ERROR_OUT_OF_HOST_MEMORY) return result;
1079            } else {
1080                if (0 != (search_prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) {
1081                    bool found_layers_in_component_meta_layer = true;
1082                    result = loader_add_meta_layer(inst, filters, search_prop, target_list, expanded_target_list, source_list,
1083                                                   &found_layers_in_component_meta_layer);
1084                    if (result == VK_ERROR_OUT_OF_HOST_MEMORY) return result;
1085                    if (!found_layers_in_component_meta_layer) found_all_component_layers = false;
1086                } else if (!loader_find_layer_name_in_list(&search_prop->info.layerName[0], target_list)) {
1087                    // Make sure the layer isn't already in the output_list, skip adding it if it is.
1088                    result = loader_add_layer_properties_to_list(inst, target_list, search_prop);
1089                    if (result == VK_ERROR_OUT_OF_HOST_MEMORY) return result;
1090                    if (NULL != expanded_target_list) {
1091                        result = loader_add_layer_properties_to_list(inst, expanded_target_list, search_prop);
1092                        if (result == VK_ERROR_OUT_OF_HOST_MEMORY) return result;
1093                    }
1094                }
1095            }
1096        } else {
1097            loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
1098                       "Failed to find layer name \"%s\" component layer \"%s\" to activate (Policy #LLP_LAYER_7)",
1099                       prop->component_layer_names.list[comp_layer], prop->component_layer_names.list[comp_layer]);
1100            found_all_component_layers = false;
1101        }
1102    }
1103
1104    // Add this layer to the overall target list (not the expanded one)
1105    if (found_all_component_layers) {
1106        result = loader_add_layer_properties_to_list(inst, target_list, prop);
1107        if (result == VK_ERROR_OUT_OF_HOST_MEMORY) return result;
1108        // Write the result to out_found_all_component_layers in case this function is being recursed
1109        if (out_found_all_component_layers) *out_found_all_component_layers = found_all_component_layers;
1110    }
1111
1112    return result;
1113}
1114
1115VkExtensionProperties *get_extension_property(const char *name, const struct loader_extension_list *list) {
1116    for (uint32_t i = 0; i < list->count; i++) {
1117        if (strcmp(name, list->list[i].extensionName) == 0) return &list->list[i];
1118    }
1119    return NULL;
1120}
1121
1122VkExtensionProperties *get_dev_extension_property(const char *name, const struct loader_device_extension_list *list) {
1123    for (uint32_t i = 0; i < list->count; i++) {
1124        if (strcmp(name, list->list[i].props.extensionName) == 0) return &list->list[i].props;
1125    }
1126    return NULL;
1127}
1128
1129// For Instance extensions implemented within the loader (i.e. DEBUG_REPORT
1130// the extension must provide two entry points for the loader to use:
1131// - "trampoline" entry point - this is the address returned by GetProcAddr
1132//                              and will always do what's necessary to support a
1133//                              global call.
1134// - "terminator" function    - this function will be put at the end of the
1135//                              instance chain and will contain the necessary logic
1136//                              to call / process the extension for the appropriate
1137//                              ICDs that are available.
1138// There is no generic mechanism for including these functions, the references
1139// must be placed into the appropriate loader entry points.
1140// GetInstanceProcAddr: call extension GetInstanceProcAddr to check for GetProcAddr
1141// requests
1142// loader_coalesce_extensions(void) - add extension records to the list of global
1143//                                    extension available to the app.
1144// instance_disp                    - add function pointer for terminator function
1145//                                    to this array.
1146// The extension itself should be in a separate file that will be linked directly
1147// with the loader.
1148VkResult loader_get_icd_loader_instance_extensions(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list,
1149                                                   struct loader_extension_list *inst_exts) {
1150    struct loader_extension_list icd_exts;
1151    VkResult res = VK_SUCCESS;
1152    char *env_value;
1153    bool filter_extensions = true;
1154
1155    // Check if a user wants to disable the instance extension filtering behavior
1156    env_value = loader_getenv("VK_LOADER_DISABLE_INST_EXT_FILTER", inst);
1157    if (NULL != env_value && atoi(env_value) != 0) {
1158        filter_extensions = false;
1159    }
1160    loader_free_getenv(env_value, inst);
1161
1162    // traverse scanned icd list adding non-duplicate extensions to the list
1163    for (uint32_t i = 0; i < icd_tramp_list->count; i++) {
1164        res = loader_init_generic_list(inst, (struct loader_generic_list *)&icd_exts, sizeof(VkExtensionProperties));
1165        if (VK_SUCCESS != res) {
1166            goto out;
1167        }
1168        res = loader_add_instance_extensions(inst, icd_tramp_list->scanned_list[i].EnumerateInstanceExtensionProperties,
1169                                             icd_tramp_list->scanned_list[i].lib_name, &icd_exts);
1170        if (VK_SUCCESS == res) {
1171            if (filter_extensions) {
1172                // Remove any extensions not recognized by the loader
1173                for (int32_t j = 0; j < (int32_t)icd_exts.count; j++) {
1174                    // See if the extension is in the list of supported extensions
1175                    bool found = false;
1176                    for (uint32_t k = 0; LOADER_INSTANCE_EXTENSIONS[k] != NULL; k++) {
1177                        if (strcmp(icd_exts.list[j].extensionName, LOADER_INSTANCE_EXTENSIONS[k]) == 0) {
1178                            found = true;
1179                            break;
1180                        }
1181                    }
1182
1183                    // If it isn't in the list, remove it
1184                    if (!found) {
1185                        for (uint32_t k = j + 1; k < icd_exts.count; k++) {
1186                            icd_exts.list[k - 1] = icd_exts.list[k];
1187                        }
1188                        --icd_exts.count;
1189                        --j;
1190                    }
1191                }
1192            }
1193
1194            res = loader_add_to_ext_list(inst, inst_exts, icd_exts.count, icd_exts.list);
1195        }
1196        loader_destroy_generic_list(inst, (struct loader_generic_list *)&icd_exts);
1197        if (VK_SUCCESS != res) {
1198            goto out;
1199        }
1200    };
1201
1202    // Traverse loader's extensions, adding non-duplicate extensions to the list
1203    res = add_debug_extensions_to_ext_list(inst, inst_exts);
1204    if (res == VK_ERROR_OUT_OF_HOST_MEMORY) {
1205        goto out;
1206    }
1207    const VkExtensionProperties portability_enumeration_extension_info[] = {
1208        {VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, VK_KHR_PORTABILITY_ENUMERATION_SPEC_VERSION}};
1209
1210    // Add VK_KHR_portability_subset
1211    res = loader_add_to_ext_list(inst, inst_exts, sizeof(portability_enumeration_extension_info) / sizeof(VkExtensionProperties),
1212                                 portability_enumeration_extension_info);
1213    if (res == VK_ERROR_OUT_OF_HOST_MEMORY) {
1214        goto out;
1215    }
1216
1217    const VkExtensionProperties direct_driver_loading_extension_info[] = {
1218        {VK_LUNARG_DIRECT_DRIVER_LOADING_EXTENSION_NAME, VK_LUNARG_DIRECT_DRIVER_LOADING_SPEC_VERSION}};
1219
1220    // Add VK_LUNARG_direct_driver_loading
1221    res = loader_add_to_ext_list(inst, inst_exts, sizeof(direct_driver_loading_extension_info) / sizeof(VkExtensionProperties),
1222                                 direct_driver_loading_extension_info);
1223    if (res == VK_ERROR_OUT_OF_HOST_MEMORY) {
1224        goto out;
1225    }
1226
1227out:
1228    return res;
1229}
1230
1231struct loader_icd_term *loader_get_icd_and_device(const void *device, struct loader_device **found_dev, uint32_t *icd_index) {
1232    VkLayerDispatchTable *dispatch_table_device = loader_get_dispatch(device);
1233    if (NULL == dispatch_table_device) {
1234        *found_dev = NULL;
1235        return NULL;
1236    }
1237    loader_platform_thread_lock_mutex(&loader_global_instance_list_lock);
1238    *found_dev = NULL;
1239
1240    for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
1241        uint32_t index = 0;
1242        for (struct loader_icd_term *icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) {
1243            for (struct loader_device *dev = icd_term->logical_device_list; dev; dev = dev->next) {
1244                // Value comparison of device prevents object wrapping by layers
1245                if (loader_get_dispatch(dev->icd_device) == dispatch_table_device ||
1246                    (dev->chain_device != VK_NULL_HANDLE && loader_get_dispatch(dev->chain_device) == dispatch_table_device)) {
1247                    *found_dev = dev;
1248                    if (NULL != icd_index) {
1249                        *icd_index = index;
1250                    }
1251                    loader_platform_thread_unlock_mutex(&loader_global_instance_list_lock);
1252                    return icd_term;
1253                }
1254            }
1255            index++;
1256        }
1257    }
1258    loader_platform_thread_unlock_mutex(&loader_global_instance_list_lock);
1259    return NULL;
1260}
1261
1262void loader_destroy_logical_device(struct loader_device *dev, const VkAllocationCallbacks *pAllocator) {
1263    if (pAllocator) {
1264        dev->alloc_callbacks = *pAllocator;
1265    }
1266    loader_device_heap_free(dev, dev);
1267}
1268
1269struct loader_device *loader_create_logical_device(const struct loader_instance *inst, const VkAllocationCallbacks *pAllocator) {
1270    struct loader_device *new_dev;
1271    new_dev = loader_calloc(pAllocator, sizeof(struct loader_device), VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
1272
1273    if (!new_dev) {
1274        loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_create_logical_device: Failed to alloc struct loader_device");
1275        return NULL;
1276    }
1277
1278    new_dev->loader_dispatch.core_dispatch.magic = DEVICE_DISP_TABLE_MAGIC_NUMBER;
1279
1280    if (pAllocator) {
1281        new_dev->alloc_callbacks = *pAllocator;
1282    }
1283
1284    return new_dev;
1285}
1286
1287void loader_add_logical_device(struct loader_icd_term *icd_term, struct loader_device *dev) {
1288    dev->next = icd_term->logical_device_list;
1289    icd_term->logical_device_list = dev;
1290}
1291
1292void loader_remove_logical_device(struct loader_icd_term *icd_term, struct loader_device *found_dev,
1293                                  const VkAllocationCallbacks *pAllocator) {
1294    struct loader_device *dev, *prev_dev;
1295
1296    if (!icd_term || !found_dev) return;
1297
1298    prev_dev = NULL;
1299    dev = icd_term->logical_device_list;
1300    while (dev && dev != found_dev) {
1301        prev_dev = dev;
1302        dev = dev->next;
1303    }
1304
1305    if (prev_dev)
1306        prev_dev->next = found_dev->next;
1307    else
1308        icd_term->logical_device_list = found_dev->next;
1309    loader_destroy_logical_device(found_dev, pAllocator);
1310}
1311
1312void loader_icd_destroy(struct loader_instance *ptr_inst, struct loader_icd_term *icd_term,
1313                        const VkAllocationCallbacks *pAllocator) {
1314    ptr_inst->total_icd_count--;
1315    for (struct loader_device *dev = icd_term->logical_device_list; dev;) {
1316        struct loader_device *next_dev = dev->next;
1317        loader_destroy_logical_device(dev, pAllocator);
1318        dev = next_dev;
1319    }
1320
1321    loader_instance_heap_free(ptr_inst, icd_term);
1322}
1323
1324struct loader_icd_term *loader_icd_add(struct loader_instance *ptr_inst, const struct loader_scanned_icd *scanned_icd) {
1325    struct loader_icd_term *icd_term;
1326
1327    icd_term = loader_instance_heap_calloc(ptr_inst, sizeof(struct loader_icd_term), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1328    if (!icd_term) {
1329        return NULL;
1330    }
1331
1332    icd_term->scanned_icd = scanned_icd;
1333    icd_term->this_instance = ptr_inst;
1334
1335    // Prepend to the list
1336    icd_term->next = ptr_inst->icd_terms;
1337    ptr_inst->icd_terms = icd_term;
1338    ptr_inst->total_icd_count++;
1339
1340    return icd_term;
1341}
1342
1343// Determine the ICD interface version to use.
1344//     @param icd
1345//     @param pVersion Output parameter indicating which version to use or 0 if
1346//            the negotiation API is not supported by the ICD
1347//     @return  bool indicating true if the selected interface version is supported
1348//            by the loader, false indicates the version is not supported
1349bool loader_get_icd_interface_version(PFN_vkNegotiateLoaderICDInterfaceVersion fp_negotiate_icd_version, uint32_t *pVersion) {
1350    if (fp_negotiate_icd_version == NULL) {
1351        // ICD does not support the negotiation API, it supports version 0 or 1
1352        // calling code must determine if it is version 0 or 1
1353        *pVersion = 0;
1354    } else {
1355        // ICD supports the negotiation API, so call it with the loader's
1356        // latest version supported
1357        *pVersion = CURRENT_LOADER_ICD_INTERFACE_VERSION;
1358        VkResult result = fp_negotiate_icd_version(pVersion);
1359
1360        if (result == VK_ERROR_INCOMPATIBLE_DRIVER) {
1361            // ICD no longer supports the loader's latest interface version so
1362            // fail loading the ICD
1363            return false;
1364        }
1365    }
1366
1367#if MIN_SUPPORTED_LOADER_ICD_INTERFACE_VERSION > 0
1368    if (*pVersion < MIN_SUPPORTED_LOADER_ICD_INTERFACE_VERSION) {
1369        // Loader no longer supports the ICD's latest interface version so fail
1370        // loading the ICD
1371        return false;
1372    }
1373#endif
1374    return true;
1375}
1376
1377void loader_scanned_icd_clear(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list) {
1378    if (0 != icd_tramp_list->capacity && icd_tramp_list->scanned_list) {
1379        for (uint32_t i = 0; i < icd_tramp_list->count; i++) {
1380            if (icd_tramp_list->scanned_list[i].handle) {
1381                loader_platform_close_library(icd_tramp_list->scanned_list[i].handle);
1382                icd_tramp_list->scanned_list[i].handle = NULL;
1383            }
1384            loader_instance_heap_free(inst, icd_tramp_list->scanned_list[i].lib_name);
1385        }
1386        loader_instance_heap_free(inst, icd_tramp_list->scanned_list);
1387    }
1388    memset(icd_tramp_list, 0, sizeof(struct loader_icd_tramp_list));
1389}
1390
1391VkResult loader_scanned_icd_init(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list) {
1392    VkResult res = VK_SUCCESS;
1393    loader_scanned_icd_clear(inst, icd_tramp_list);
1394    icd_tramp_list->capacity = 8 * sizeof(struct loader_scanned_icd);
1395    icd_tramp_list->scanned_list = loader_instance_heap_alloc(inst, icd_tramp_list->capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1396    if (NULL == icd_tramp_list->scanned_list) {
1397        loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
1398                   "loader_scanned_icd_init: Realloc failed for layer list when attempting to add new layer");
1399        res = VK_ERROR_OUT_OF_HOST_MEMORY;
1400    }
1401    return res;
1402}
1403
1404VkResult loader_add_direct_driver(const struct loader_instance *inst, uint32_t index,
1405                                  const VkDirectDriverLoadingInfoLUNARG *pDriver, struct loader_icd_tramp_list *icd_tramp_list) {
1406    // Assume pDriver is valid, since there is no real way to check it. Calling code should make sure the pointer to the array
1407    // of VkDirectDriverLoadingInfoLUNARG structures is non-null.
1408    if (NULL == pDriver->pfnGetInstanceProcAddr) {
1409        loader_log(
1410            inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
1411            "loader_add_direct_driver: VkDirectDriverLoadingInfoLUNARG structure at index %d contains a NULL pointer for the "
1412            "pfnGetInstanceProcAddr member, skipping.",
1413            index);
1414        return VK_ERROR_INITIALIZATION_FAILED;
1415    }
1416
1417    PFN_vkGetInstanceProcAddr fp_get_proc_addr = pDriver->pfnGetInstanceProcAddr;
1418    PFN_vkCreateInstance fp_create_inst = NULL;
1419    PFN_vkEnumerateInstanceExtensionProperties fp_get_inst_ext_props = NULL;
1420    PFN_GetPhysicalDeviceProcAddr fp_get_phys_dev_proc_addr = NULL;
1421    PFN_vkNegotiateLoaderICDInterfaceVersion fp_negotiate_icd_version = NULL;
1422#if defined(VK_USE_PLATFORM_WIN32_KHR)
1423    PFN_vk_icdEnumerateAdapterPhysicalDevices fp_enum_dxgi_adapter_phys_devs = NULL;
1424#endif
1425    struct loader_scanned_icd *new_scanned_icd;
1426    uint32_t interface_version = 0;
1427
1428    // Try to get the negotiate ICD interface version function
1429    fp_negotiate_icd_version = (PFN_vk_icdNegotiateLoaderICDInterfaceVersion)pDriver->pfnGetInstanceProcAddr(
1430        NULL, "vk_icdNegotiateLoaderICDInterfaceVersion");
1431
1432    if (NULL == fp_negotiate_icd_version) {
1433        loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
1434                   "loader_add_direct_driver: Could not get 'vk_icdNegotiateLoaderICDInterfaceVersion' from "
1435                   "VkDirectDriverLoadingInfoLUNARG structure at "
1436                   "index %d, skipping.",
1437                   index);
1438        return VK_ERROR_INITIALIZATION_FAILED;
1439    }
1440
1441    if (!loader_get_icd_interface_version(fp_negotiate_icd_version, &interface_version)) {
1442        loader_log(
1443            inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
1444            "loader_add_direct_driver: VkDirectDriverLoadingInfoLUNARG structure at index %d supports interface version %d, "
1445            "which is incompatible with the Loader Driver Interface version that supports the VK_LUNARG_direct_driver_loading "
1446            "extension, skipping.",
1447            index, interface_version);
1448        return VK_ERROR_INITIALIZATION_FAILED;
1449    }
1450
1451    if (interface_version < 7) {
1452        loader_log(
1453            inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
1454            "loader_add_direct_driver: VkDirectDriverLoadingInfoLUNARG structure at index %d supports interface version %d, "
1455            "which is incompatible with the Loader Driver Interface version that supports the VK_LUNARG_direct_driver_loading "
1456            "extension, skipping.",
1457            index, interface_version);
1458        return VK_ERROR_INITIALIZATION_FAILED;
1459    }
1460
1461    fp_create_inst = (PFN_vkCreateInstance)pDriver->pfnGetInstanceProcAddr(NULL, "vkCreateInstance");
1462    if (NULL == fp_create_inst) {
1463        loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
1464                   "loader_add_direct_driver: Could not get 'vkCreateInstance' from VkDirectDriverLoadingInfoLUNARG structure at "
1465                   "index %d, skipping.",
1466                   index);
1467        return VK_ERROR_INITIALIZATION_FAILED;
1468    }
1469    fp_get_inst_ext_props =
1470        (PFN_vkEnumerateInstanceExtensionProperties)pDriver->pfnGetInstanceProcAddr(NULL, "vkEnumerateInstanceExtensionProperties");
1471    if (NULL == fp_get_inst_ext_props) {
1472        loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
1473                   "loader_add_direct_driver: Could not get 'vkEnumerateInstanceExtensionProperties' from "
1474                   "VkDirectDriverLoadingInfoLUNARG structure at index %d, skipping.",
1475                   index);
1476        return VK_ERROR_INITIALIZATION_FAILED;
1477    }
1478
1479    fp_get_phys_dev_proc_addr =
1480        (PFN_vk_icdGetPhysicalDeviceProcAddr)pDriver->pfnGetInstanceProcAddr(NULL, "vk_icdGetPhysicalDeviceProcAddr");
1481#if defined(VK_USE_PLATFORM_WIN32_KHR)
1482    // Query "vk_icdEnumerateAdapterPhysicalDevices" with vk_icdGetInstanceProcAddr if the library reports interface version
1483    // 7 or greater, otherwise fallback to loading it from the platform dynamic linker
1484    fp_enum_dxgi_adapter_phys_devs =
1485        (PFN_vk_icdEnumerateAdapterPhysicalDevices)pDriver->pfnGetInstanceProcAddr(NULL, "vk_icdEnumerateAdapterPhysicalDevices");
1486#endif
1487
1488    // check for enough capacity
1489    if ((icd_tramp_list->count * sizeof(struct loader_scanned_icd)) >= icd_tramp_list->capacity) {
1490        void *new_ptr = loader_instance_heap_realloc(inst, icd_tramp_list->scanned_list, icd_tramp_list->capacity,
1491                                                     icd_tramp_list->capacity * 2, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1492        if (NULL == new_ptr) {
1493            loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
1494                       "loader_add_direct_driver: Realloc failed on icd library list for ICD index %u", index);
1495            return VK_ERROR_OUT_OF_HOST_MEMORY;
1496        }
1497        icd_tramp_list->scanned_list = new_ptr;
1498
1499        // double capacity
1500        icd_tramp_list->capacity *= 2;
1501    }
1502
1503    // Driver must be 1.1 to support version 7
1504    uint32_t api_version = VK_API_VERSION_1_1;
1505    PFN_vkEnumerateInstanceVersion icd_enumerate_instance_version =
1506        (PFN_vkEnumerateInstanceVersion)pDriver->pfnGetInstanceProcAddr(NULL, "vkEnumerateInstanceVersion");
1507
1508    if (icd_enumerate_instance_version) {
1509        VkResult res = icd_enumerate_instance_version(&api_version);
1510        if (res != VK_SUCCESS) {
1511            return res;
1512        }
1513    }
1514
1515    new_scanned_icd = &(icd_tramp_list->scanned_list[icd_tramp_list->count]);
1516    new_scanned_icd->handle = NULL;
1517    new_scanned_icd->api_version = api_version;
1518    new_scanned_icd->GetInstanceProcAddr = fp_get_proc_addr;
1519    new_scanned_icd->GetPhysicalDeviceProcAddr = fp_get_phys_dev_proc_addr;
1520    new_scanned_icd->EnumerateInstanceExtensionProperties = fp_get_inst_ext_props;
1521    new_scanned_icd->CreateInstance = fp_create_inst;
1522#if defined(VK_USE_PLATFORM_WIN32_KHR)
1523    new_scanned_icd->EnumerateAdapterPhysicalDevices = fp_enum_dxgi_adapter_phys_devs;
1524#endif
1525    new_scanned_icd->interface_version = interface_version;
1526
1527    new_scanned_icd->lib_name = NULL;
1528    icd_tramp_list->count++;
1529
1530    loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
1531               "loader_add_direct_driver: Adding driver found in index %d of "
1532               "VkDirectDriverLoadingListLUNARG::pDrivers structure. pfnGetInstanceProcAddr was set to %p",
1533               index, pDriver->pfnGetInstanceProcAddr);
1534
1535    return VK_SUCCESS;
1536}
1537
1538// Search through VkInstanceCreateInfo's pNext chain for any drivers from the direct driver loading extension and load them.
1539VkResult loader_scan_for_direct_drivers(const struct loader_instance *inst, const VkInstanceCreateInfo *pCreateInfo,
1540                                        struct loader_icd_tramp_list *icd_tramp_list, bool *direct_driver_loading_exclusive_mode) {
1541    if (NULL == pCreateInfo) {
1542        // Don't do this logic unless we are being called from vkCreateInstance, when pCreateInfo will be non-null
1543        return VK_SUCCESS;
1544    }
1545    bool direct_driver_loading_enabled = false;
1546    // Try to if VK_LUNARG_direct_driver_loading is enabled and if we are using it exclusively
1547    // Skip this step if inst is NULL, aka when this function is being called before instance creation
1548    if (inst != NULL && pCreateInfo->ppEnabledExtensionNames && pCreateInfo->enabledExtensionCount > 0) {
1549        // Look through the enabled extension list, make sure VK_LUNARG_direct_driver_loading is present
1550        for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
1551            if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_LUNARG_DIRECT_DRIVER_LOADING_EXTENSION_NAME) == 0) {
1552                direct_driver_loading_enabled = true;
1553                break;
1554            }
1555        }
1556    }
1557    const VkDirectDriverLoadingListLUNARG *ddl_list = NULL;
1558    // Find the VkDirectDriverLoadingListLUNARG struct in the pNext chain of vkInstanceCreateInfo
1559    const VkBaseOutStructure *chain = pCreateInfo->pNext;
1560    while (chain) {
1561        if (chain->sType == VK_STRUCTURE_TYPE_DIRECT_DRIVER_LOADING_LIST_LUNARG) {
1562            ddl_list = (VkDirectDriverLoadingListLUNARG *)chain;
1563            break;
1564        }
1565        chain = (const VkBaseOutStructure *)chain->pNext;
1566    }
1567    if (NULL == ddl_list) {
1568        if (direct_driver_loading_enabled) {
1569            loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
1570                       "loader_scan_for_direct_drivers: The VK_LUNARG_direct_driver_loading extension was enabled but the "
1571                       "pNext chain of "
1572                       "VkInstanceCreateInfo did not contain the "
1573                       "VkDirectDriverLoadingListLUNARG structure.");
1574        }
1575        // Always want to exit early if there was no VkDirectDriverLoadingListLUNARG in the pNext chain
1576        return VK_SUCCESS;
1577    }
1578
1579    if (!direct_driver_loading_enabled) {
1580        loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
1581                   "loader_scan_for_direct_drivers: The pNext chain of VkInstanceCreateInfo contained the "
1582                   "VkDirectDriverLoadingListLUNARG structure, but the VK_LUNARG_direct_driver_loading extension was "
1583                   "not enabled.");
1584        return VK_SUCCESS;
1585    }
1586    // If we are using exclusive mode, skip looking for any more drivers from system or environment variables
1587    if (ddl_list->mode == VK_DIRECT_DRIVER_LOADING_MODE_EXCLUSIVE_LUNARG) {
1588        *direct_driver_loading_exclusive_mode = true;
1589        loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
1590                   "loader_scan_for_direct_drivers: The VK_LUNARG_direct_driver_loading extension is active and specified "
1591                   "VK_DIRECT_DRIVER_LOADING_MODE_EXCLUSIVE_LUNARG, skipping system and environment "
1592                   "variable driver search mechanisms.");
1593    }
1594    if (NULL == ddl_list->pDrivers) {
1595        loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
1596                   "loader_scan_for_direct_drivers: The VkDirectDriverLoadingListLUNARG structure in the pNext chain of "
1597                   "VkInstanceCreateInfo has a NULL pDrivers member.");
1598        return VK_SUCCESS;
1599    }
1600    if (ddl_list->driverCount == 0) {
1601        loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
1602                   "loader_scan_for_direct_drivers: The VkDirectDriverLoadingListLUNARG structure in the pNext chain of "
1603                   "VkInstanceCreateInfo has a non-null pDrivers member but a driverCount member with a value "
1604                   "of zero.");
1605        return VK_SUCCESS;
1606    }
1607    // Go through all VkDirectDriverLoadingInfoLUNARG entries and add each driver
1608    // Because icd_tramp's are prepended, this will result in the drivers appearing at the end
1609    for (uint32_t i = 0; i < ddl_list->driverCount; i++) {
1610        VkResult res = loader_add_direct_driver(inst, i, &ddl_list->pDrivers[i], icd_tramp_list);
1611        if (res == VK_ERROR_OUT_OF_HOST_MEMORY) {
1612            return res;
1613        }
1614    }
1615
1616    return VK_SUCCESS;
1617}
1618
1619VkResult loader_scanned_icd_add(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list,
1620                                const char *filename, uint32_t api_version, enum loader_layer_library_status *lib_status) {
1621    loader_platform_dl_handle handle = NULL;
1622    PFN_vkCreateInstance fp_create_inst = NULL;
1623    PFN_vkEnumerateInstanceExtensionProperties fp_get_inst_ext_props = NULL;
1624    PFN_vkGetInstanceProcAddr fp_get_proc_addr = NULL;
1625    PFN_GetPhysicalDeviceProcAddr fp_get_phys_dev_proc_addr = NULL;
1626    PFN_vkNegotiateLoaderICDInterfaceVersion fp_negotiate_icd_version = NULL;
1627#if defined(VK_USE_PLATFORM_WIN32_KHR)
1628    PFN_vk_icdEnumerateAdapterPhysicalDevices fp_enum_dxgi_adapter_phys_devs = NULL;
1629#endif
1630    struct loader_scanned_icd *new_scanned_icd = NULL;
1631    uint32_t interface_vers;
1632    VkResult res = VK_SUCCESS;
1633
1634    // This shouldn't happen, but the check is necessary because dlopen returns a handle to the main program when
1635    // filename is NULL
1636    if (filename == NULL) {
1637        loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_scanned_icd_add: A NULL filename was used, skipping this ICD",
1638                   filename);
1639        res = VK_ERROR_INCOMPATIBLE_DRIVER;
1640        goto out;
1641    }
1642
1643// TODO implement smarter opening/closing of libraries. For now this
1644// function leaves libraries open and the scanned_icd_clear closes them
1645#if defined(__Fuchsia__)
1646    handle = loader_platform_open_driver(filename);
1647#else
1648    handle = loader_platform_open_library(filename);
1649#endif
1650    if (NULL == handle) {
1651        loader_handle_load_library_error(inst, filename, lib_status);
1652        if (lib_status && *lib_status == LOADER_LAYER_LIB_ERROR_OUT_OF_MEMORY) {
1653            res = VK_ERROR_OUT_OF_HOST_MEMORY;
1654        } else {
1655            res = VK_ERROR_INCOMPATIBLE_DRIVER;
1656        }
1657        goto out;
1658    }
1659
1660    // Try to load the driver's exported vk_icdNegotiateLoaderICDInterfaceVersion
1661    fp_negotiate_icd_version = loader_platform_get_proc_address(handle, "vk_icdNegotiateLoaderICDInterfaceVersion");
1662
1663    // If it isn't exported, we are dealing with either a v0, v1, or a v7 and up driver
1664    if (NULL == fp_negotiate_icd_version) {
1665        // Try to load the driver's exported vk_icdGetInstanceProcAddr - if this is a v7 or up driver, we can use it to get
1666        // the driver's vk_icdNegotiateLoaderICDInterfaceVersion function
1667        fp_get_proc_addr = loader_platform_get_proc_address(handle, "vk_icdGetInstanceProcAddr");
1668
1669        // If we successfully loaded vk_icdGetInstanceProcAddr, try to get vk_icdNegotiateLoaderICDInterfaceVersion
1670        if (fp_get_proc_addr) {
1671            fp_negotiate_icd_version =
1672                (PFN_vk_icdNegotiateLoaderICDInterfaceVersion)fp_get_proc_addr(NULL, "vk_icdNegotiateLoaderICDInterfaceVersion");
1673        }
1674    }
1675
1676    // Try to negotiate the Loader and Driver Interface Versions
1677    // loader_get_icd_interface_version will check if fp_negotiate_icd_version is NULL, so we don't have to.
1678    // If it *is* NULL, that means this driver uses interface version 0 or 1
1679    if (!loader_get_icd_interface_version(fp_negotiate_icd_version, &interface_vers)) {
1680        loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
1681                   "loader_scanned_icd_add: ICD %s doesn't support interface version compatible with loader, skip this ICD.",
1682                   filename);
1683        goto out;
1684    }
1685
1686    // If we didn't already query vk_icdGetInstanceProcAddr, try now
1687    if (NULL == fp_get_proc_addr) {
1688        fp_get_proc_addr = loader_platform_get_proc_address(handle, "vk_icdGetInstanceProcAddr");
1689    }
1690
1691    // If vk_icdGetInstanceProcAddr is NULL, this ICD is using version 0 and so we should respond accordingly.
1692    if (NULL == fp_get_proc_addr) {
1693        // Exporting vk_icdNegotiateLoaderICDInterfaceVersion but not vk_icdGetInstanceProcAddr violates Version 2's
1694        // requirements, as for Version 2 to be supported Version 1 must also be supported
1695        if (interface_vers != 0) {
1696            loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
1697                       "loader_scanned_icd_add: ICD %s reports an interface version of %d but doesn't export "
1698                       "vk_icdGetInstanceProcAddr, skip this ICD.",
1699                       filename, interface_vers);
1700            goto out;
1701        }
1702        // Use deprecated interface from version 0
1703        fp_get_proc_addr = loader_platform_get_proc_address(handle, "vkGetInstanceProcAddr");
1704        if (NULL == fp_get_proc_addr) {
1705            loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
1706                       "loader_scanned_icd_add: Attempt to retrieve either \'vkGetInstanceProcAddr\' or "
1707                       "\'vk_icdGetInstanceProcAddr\' from ICD %s failed.",
1708                       filename);
1709            goto out;
1710        } else {
1711            loader_log(inst, VULKAN_LOADER_WARN_BIT, 0,
1712                       "loader_scanned_icd_add: Using deprecated ICD interface of \'vkGetInstanceProcAddr\' instead of "
1713                       "\'vk_icdGetInstanceProcAddr\' for ICD %s",
1714                       filename);
1715        }
1716        fp_create_inst = loader_platform_get_proc_address(handle, "vkCreateInstance");
1717        if (NULL == fp_create_inst) {
1718            loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
1719                       "loader_scanned_icd_add:  Failed querying \'vkCreateInstance\' via dlsym/LoadLibrary for ICD %s", filename);
1720            goto out;
1721        }
1722        fp_get_inst_ext_props = loader_platform_get_proc_address(handle, "vkEnumerateInstanceExtensionProperties");
1723        if (NULL == fp_get_inst_ext_props) {
1724            loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
1725                       "loader_scanned_icd_add: Could not get \'vkEnumerateInstanceExtensionProperties\' via dlsym/LoadLibrary "
1726                       "for ICD %s",
1727                       filename);
1728            goto out;
1729        }
1730    } else {
1731        // vk_icdGetInstanceProcAddr was successfully found, we can assume the version is at least one
1732        // If vk_icdNegotiateLoaderICDInterfaceVersion was also found, interface_vers must be 2 or greater, so this check is
1733        // fine
1734        if (interface_vers == 0) {
1735            interface_vers = 1;
1736        }
1737
1738        fp_create_inst = (PFN_vkCreateInstance)fp_get_proc_addr(NULL, "vkCreateInstance");
1739        if (NULL == fp_create_inst) {
1740            loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
1741                       "loader_scanned_icd_add: Could not get \'vkCreateInstance\' via \'vk_icdGetInstanceProcAddr\' for ICD %s",
1742                       filename);
1743            goto out;
1744        }
1745        fp_get_inst_ext_props =
1746            (PFN_vkEnumerateInstanceExtensionProperties)fp_get_proc_addr(NULL, "vkEnumerateInstanceExtensionProperties");
1747        if (NULL == fp_get_inst_ext_props) {
1748            loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
1749                       "loader_scanned_icd_add: Could not get \'vkEnumerateInstanceExtensionProperties\' via "
1750                       "\'vk_icdGetInstanceProcAddr\' for ICD %s",
1751                       filename);
1752            goto out;
1753        }
1754        // Query "vk_icdGetPhysicalDeviceProcAddr" with vk_icdGetInstanceProcAddr if the library reports interface version 7 or
1755        // greater, otherwise fallback to loading it from the platform dynamic linker
1756        if (interface_vers >= 7) {
1757            fp_get_phys_dev_proc_addr =
1758                (PFN_vk_icdGetPhysicalDeviceProcAddr)fp_get_proc_addr(NULL, "vk_icdGetPhysicalDeviceProcAddr");
1759        }
1760        if (NULL == fp_get_phys_dev_proc_addr && interface_vers >= 3) {
1761            fp_get_phys_dev_proc_addr = loader_platform_get_proc_address(handle, "vk_icdGetPhysicalDeviceProcAddr");
1762        }
1763#if defined(VK_USE_PLATFORM_WIN32_KHR)
1764        // Query "vk_icdEnumerateAdapterPhysicalDevices" with vk_icdGetInstanceProcAddr if the library reports interface version
1765        // 7 or greater, otherwise fallback to loading it from the platform dynamic linker
1766        if (interface_vers >= 7) {
1767            fp_enum_dxgi_adapter_phys_devs =
1768                (PFN_vk_icdEnumerateAdapterPhysicalDevices)fp_get_proc_addr(NULL, "vk_icdEnumerateAdapterPhysicalDevices");
1769        }
1770        if (NULL == fp_enum_dxgi_adapter_phys_devs && interface_vers >= 6) {
1771            fp_enum_dxgi_adapter_phys_devs = loader_platform_get_proc_address(handle, "vk_icdEnumerateAdapterPhysicalDevices");
1772        }
1773#endif
1774    }
1775
1776    // check for enough capacity
1777    if ((icd_tramp_list->count * sizeof(struct loader_scanned_icd)) >= icd_tramp_list->capacity) {
1778        void *new_ptr = loader_instance_heap_realloc(inst, icd_tramp_list->scanned_list, icd_tramp_list->capacity,
1779                                                     icd_tramp_list->capacity * 2, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1780        if (NULL == new_ptr) {
1781            res = VK_ERROR_OUT_OF_HOST_MEMORY;
1782            loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_scanned_icd_add: Realloc failed on icd library list for ICD %s",
1783                       filename);
1784            goto out;
1785        }
1786        icd_tramp_list->scanned_list = new_ptr;
1787
1788        // double capacity
1789        icd_tramp_list->capacity *= 2;
1790    }
1791
1792    loader_api_version api_version_struct = loader_make_version(api_version);
1793    if (interface_vers <= 4 && loader_check_version_meets_required(LOADER_VERSION_1_1_0, api_version_struct)) {
1794        loader_log(inst, VULKAN_LOADER_WARN_BIT, 0,
1795                   "loader_scanned_icd_add: Driver %s supports Vulkan %u.%u, but only supports loader interface version %u."
1796                   " Interface version 5 or newer required to support this version of Vulkan (Policy #LDP_DRIVER_7)",
1797                   filename, api_version_struct.major, api_version_struct.minor, interface_vers);
1798    }
1799
1800    new_scanned_icd = &(icd_tramp_list->scanned_list[icd_tramp_list->count]);
1801    new_scanned_icd->handle = handle;
1802    new_scanned_icd->api_version = api_version;
1803    new_scanned_icd->GetInstanceProcAddr = fp_get_proc_addr;
1804    new_scanned_icd->GetPhysicalDeviceProcAddr = fp_get_phys_dev_proc_addr;
1805    new_scanned_icd->EnumerateInstanceExtensionProperties = fp_get_inst_ext_props;
1806    new_scanned_icd->CreateInstance = fp_create_inst;
1807#if defined(VK_USE_PLATFORM_WIN32_KHR)
1808    new_scanned_icd->EnumerateAdapterPhysicalDevices = fp_enum_dxgi_adapter_phys_devs;
1809#endif
1810    new_scanned_icd->interface_version = interface_vers;
1811
1812    res = loader_copy_to_new_str(inst, filename, &new_scanned_icd->lib_name);
1813    if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
1814        loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_scanned_icd_add: Out of memory can't add ICD %s", filename);
1815        goto out;
1816    }
1817    icd_tramp_list->count++;
1818
1819out:
1820
1821    return res;
1822}
1823
1824void loader_initialize(void) {
1825    // initialize mutexes
1826    loader_platform_thread_create_mutex(&loader_lock);
1827    loader_platform_thread_create_mutex(&loader_preload_icd_lock);
1828    loader_platform_thread_create_mutex(&loader_global_instance_list_lock);
1829    init_global_loader_settings();
1830
1831    // initialize logging
1832    loader_init_global_debug_level();
1833#if defined(_WIN32)
1834    windows_initialization();
1835#endif
1836
1837    loader_api_version version = loader_make_full_version(VK_HEADER_VERSION_COMPLETE);
1838    loader_log(NULL, VULKAN_LOADER_INFO_BIT, 0, "Vulkan Loader Version %d.%d.%d", version.major, version.minor, version.patch);
1839
1840#if defined(GIT_BRANCH_NAME) && defined(GIT_TAG_INFO)
1841    loader_log(NULL, VULKAN_LOADER_INFO_BIT, 0, "[Vulkan Loader Git - Tag: " GIT_BRANCH_NAME ", Branch/Commit: " GIT_TAG_INFO "]");
1842#endif
1843
1844    char *loader_disable_dynamic_library_unloading_env_var = loader_getenv("VK_LOADER_DISABLE_DYNAMIC_LIBRARY_UNLOADING", NULL);
1845    if (loader_disable_dynamic_library_unloading_env_var &&
1846        0 == strncmp(loader_disable_dynamic_library_unloading_env_var, "1", 2)) {
1847        loader_disable_dynamic_library_unloading = true;
1848        loader_log(NULL, VULKAN_LOADER_WARN_BIT, 0, "Vulkan Loader: library unloading is disabled");
1849    } else {
1850        loader_disable_dynamic_library_unloading = false;
1851    }
1852    loader_free_getenv(loader_disable_dynamic_library_unloading_env_var, NULL);
1853#if defined(LOADER_USE_UNSAFE_FILE_SEARCH)
1854    loader_log(NULL, VULKAN_LOADER_WARN_BIT, 0, "Vulkan Loader: unsafe searching is enabled");
1855#endif
1856}
1857
1858void loader_release() {
1859    // Guarantee release of the preloaded ICD libraries. This may have already been called in vkDestroyInstance.
1860    loader_unload_preloaded_icds();
1861
1862    // release mutexes
1863    teardown_global_loader_settings();
1864    loader_platform_thread_delete_mutex(&loader_lock);
1865    loader_platform_thread_delete_mutex(&loader_preload_icd_lock);
1866    loader_platform_thread_delete_mutex(&loader_global_instance_list_lock);
1867}
1868
1869// Preload the ICD libraries that are likely to be needed so we don't repeatedly load/unload them later
1870void loader_preload_icds(void) {
1871    loader_platform_thread_lock_mutex(&loader_preload_icd_lock);
1872
1873    // Already preloaded, skip loading again.
1874    if (scanned_icds.scanned_list != NULL) {
1875        loader_platform_thread_unlock_mutex(&loader_preload_icd_lock);
1876        return;
1877    }
1878
1879    VkResult result = loader_icd_scan(NULL, &scanned_icds, NULL, NULL);
1880    if (result != VK_SUCCESS) {
1881        loader_scanned_icd_clear(NULL, &scanned_icds);
1882    }
1883    loader_platform_thread_unlock_mutex(&loader_preload_icd_lock);
1884}
1885
1886// Release the ICD libraries that were preloaded
1887void loader_unload_preloaded_icds(void) {
1888    loader_platform_thread_lock_mutex(&loader_preload_icd_lock);
1889    loader_scanned_icd_clear(NULL, &scanned_icds);
1890    loader_platform_thread_unlock_mutex(&loader_preload_icd_lock);
1891}
1892
1893#if !defined(_WIN32)
1894__attribute__((constructor)) void loader_init_library(void) { loader_initialize(); }
1895
1896__attribute__((destructor)) void loader_free_library(void) { loader_release(); }
1897#endif
1898
1899// Get next file or dirname given a string list or registry key path
1900//
1901// \returns
1902// A pointer to first char in the next path.
1903// The next path (or NULL) in the list is returned in next_path.
1904// Note: input string is modified in some cases. PASS IN A COPY!
1905char *loader_get_next_path(char *path) {
1906    uint32_t len;
1907    char *next;
1908
1909    if (path == NULL) return NULL;
1910    next = strchr(path, PATH_SEPARATOR);
1911    if (next == NULL) {
1912        len = (uint32_t)strlen(path);
1913        next = path + len;
1914    } else {
1915        *next = '\0';
1916        next++;
1917    }
1918
1919    return next;
1920}
1921
1922/* Processes a json manifest's library_path and the location of the json manifest to create the path of the library
1923 * The output is stored in out_fullpath by allocating a string - so its the caller's responsibility to free it
1924 * The output is the combination of the base path of manifest_file_path concatenated with library path
1925 * If library_path is an absolute path, we do not prepend the base path of manifest_file_path
1926 *
1927 * This function takes ownership of library_path - caller does not need to worry about freeing it.
1928 */
1929VkResult combine_manifest_directory_and_library_path(const struct loader_instance *inst, char *library_path,
1930                                                     const char *manifest_file_path, char **out_fullpath) {
1931    assert(library_path && manifest_file_path && out_fullpath);
1932    if (loader_platform_is_path_absolute(library_path)) {
1933        *out_fullpath = library_path;
1934        return VK_SUCCESS;
1935    }
1936    VkResult res = VK_SUCCESS;
1937
1938    size_t library_path_len = strlen(library_path);
1939    size_t manifest_file_path_str_len = strlen(manifest_file_path);
1940    bool library_path_contains_directory_symbol = false;
1941    for (size_t i = 0; i < library_path_len; i++) {
1942        if (library_path[i] == DIRECTORY_SYMBOL) {
1943            library_path_contains_directory_symbol = true;
1944            break;
1945        }
1946    }
1947    // Means that the library_path is neither absolute nor relative - thus we should not modify it at all
1948    if (!library_path_contains_directory_symbol) {
1949        *out_fullpath = library_path;
1950        return VK_SUCCESS;
1951    }
1952    // must include both a directory symbol and the null terminator
1953    size_t new_str_len = library_path_len + manifest_file_path_str_len + 1 + 1;
1954
1955    *out_fullpath = loader_instance_heap_calloc(inst, new_str_len, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1956    if (NULL == *out_fullpath) {
1957        res = VK_ERROR_OUT_OF_HOST_MEMORY;
1958        goto out;
1959    }
1960    size_t cur_loc_in_out_fullpath = 0;
1961    // look for the last occurrence of DIRECTORY_SYMBOL in manifest_file_path
1962    size_t last_directory_symbol = 0;
1963    bool found_directory_symbol = false;
1964    for (size_t i = 0; i < manifest_file_path_str_len; i++) {
1965        if (manifest_file_path[i] == DIRECTORY_SYMBOL) {
1966            last_directory_symbol = i + 1;  // we want to include the symbol
1967            found_directory_symbol = true;
1968            // dont break because we want to find the last occurrence
1969        }
1970    }
1971    // Add manifest_file_path up to the last directory symbol
1972    if (found_directory_symbol) {
1973        loader_strncpy(*out_fullpath, new_str_len, manifest_file_path, last_directory_symbol);
1974        cur_loc_in_out_fullpath += last_directory_symbol;
1975    }
1976    loader_strncpy(&(*out_fullpath)[cur_loc_in_out_fullpath], new_str_len - cur_loc_in_out_fullpath, library_path,
1977                   library_path_len);
1978    cur_loc_in_out_fullpath += library_path_len + 1;
1979    (*out_fullpath)[cur_loc_in_out_fullpath] = '\0';
1980
1981out:
1982    loader_instance_heap_free(inst, library_path);
1983
1984    return res;
1985}
1986
1987// Given a filename (file)  and a list of paths (in_dirs), try to find an existing
1988// file in the paths.  If filename already is a path then no searching in the given paths.
1989//
1990// @return - A string in out_fullpath of either the full path or file.
1991void loader_get_fullpath(const char *file, const char *in_dirs, size_t out_size, char *out_fullpath) {
1992    if (!loader_platform_is_path(file) && *in_dirs) {
1993        size_t dirs_copy_len = strlen(in_dirs) + 1;
1994        char *dirs_copy = loader_stack_alloc(dirs_copy_len);
1995        loader_strncpy(dirs_copy, dirs_copy_len, in_dirs, dirs_copy_len);
1996
1997        // find if file exists after prepending paths in given list
1998        // for (dir = dirs_copy; *dir && (next_dir = loader_get_next_path(dir)); dir = next_dir) {
1999        char *dir = dirs_copy;
2000        char *next_dir = loader_get_next_path(dir);
2001        while (*dir && next_dir) {
2002            int path_concat_ret = snprintf(out_fullpath, out_size, "%s%c%s", dir, DIRECTORY_SYMBOL, file);
2003            if (path_concat_ret < 0) {
2004                continue;
2005            }
2006            if (loader_platform_file_exists(out_fullpath)) {
2007                return;
2008            }
2009            dir = next_dir;
2010            next_dir = loader_get_next_path(dir);
2011        }
2012    }
2013
2014    (void)snprintf(out_fullpath, out_size, "%s", file);
2015}
2016
2017// Verify that all component layers in a meta-layer are valid.
2018bool verify_meta_layer_component_layers(const struct loader_instance *inst, struct loader_layer_properties *prop,
2019                                        struct loader_layer_list *instance_layers) {
2020    loader_api_version meta_layer_version = loader_make_version(prop->info.specVersion);
2021
2022    for (uint32_t comp_layer = 0; comp_layer < prop->component_layer_names.count; comp_layer++) {
2023        struct loader_layer_properties *comp_prop =
2024            loader_find_layer_property(prop->component_layer_names.list[comp_layer], instance_layers);
2025        if (comp_prop == NULL) {
2026            loader_log(inst, VULKAN_LOADER_WARN_BIT, 0,
2027                       "verify_meta_layer_component_layers: Meta-layer %s can't find component layer %s at index %d."
2028                       "  Skipping this layer.",
2029                       prop->info.layerName, prop->component_layer_names.list[comp_layer], comp_layer);
2030
2031            return false;
2032        }
2033
2034        // Check the version of each layer, they need to be at least MAJOR and MINOR
2035        loader_api_version comp_prop_version = loader_make_version(comp_prop->info.specVersion);
2036        if (!loader_check_version_meets_required(meta_layer_version, comp_prop_version)) {
2037            loader_log(inst, VULKAN_LOADER_WARN_BIT, 0,
2038                       "verify_meta_layer_component_layers: Meta-layer uses API version %d.%d, but component "
2039                       "layer %d has API version %d.%d that is lower.  Skipping this layer.",
2040                       meta_layer_version.major, meta_layer_version.minor, comp_layer, comp_prop_version.major,
2041                       comp_prop_version.minor);
2042
2043            return false;
2044        }
2045
2046        // Make sure the layer isn't using it's own name
2047        if (!strcmp(prop->info.layerName, prop->component_layer_names.list[comp_layer])) {
2048            loader_log(inst, VULKAN_LOADER_WARN_BIT, 0,
2049                       "verify_meta_layer_component_layers: Meta-layer %s lists itself in its component layer "
2050                       "list at index %d.  Skipping this layer.",
2051                       prop->info.layerName, comp_layer);
2052
2053            return false;
2054        }
2055        if (comp_prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER) {
2056            loader_log(inst, VULKAN_LOADER_INFO_BIT, 0,
2057                       "verify_meta_layer_component_layers: Adding meta-layer %s which also contains meta-layer %s",
2058                       prop->info.layerName, comp_prop->info.layerName);
2059
2060            // Make sure if the layer is using a meta-layer in its component list that we also verify that.
2061            if (!verify_meta_layer_component_layers(inst, comp_prop, instance_layers)) {
2062                loader_log(inst, VULKAN_LOADER_WARN_BIT, 0,
2063                           "Meta-layer %s component layer %s can not find all component layers."
2064                           "  Skipping this layer.",
2065                           prop->info.layerName, prop->component_layer_names.list[comp_layer]);
2066                return false;
2067            }
2068        }
2069    }
2070    // Didn't exit early so that means it passed all checks
2071    loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_LAYER_BIT, 0,
2072               "Meta-layer \"%s\" all %d component layers appear to be valid.", prop->info.layerName,
2073               prop->component_layer_names.count);
2074
2075    // If layer logging is on, list the internals included in the meta-layer
2076    for (uint32_t comp_layer = 0; comp_layer < prop->component_layer_names.count; comp_layer++) {
2077        loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, "  [%d] %s", comp_layer, prop->component_layer_names.list[comp_layer]);
2078    }
2079    return true;
2080}
2081
2082// Add any instance and device extensions from component layers to this layer
2083// list, so that anyone querying extensions will only need to look at the meta-layer
2084bool update_meta_layer_extensions_from_component_layers(const struct loader_instance *inst, struct loader_layer_properties *prop,
2085                                                        struct loader_layer_list *instance_layers) {
2086    VkResult res = VK_SUCCESS;
2087    for (uint32_t comp_layer = 0; comp_layer < prop->component_layer_names.count; comp_layer++) {
2088        struct loader_layer_properties *comp_prop =
2089            loader_find_layer_property(prop->component_layer_names.list[comp_layer], instance_layers);
2090
2091        if (NULL != comp_prop->instance_extension_list.list) {
2092            for (uint32_t ext = 0; ext < comp_prop->instance_extension_list.count; ext++) {
2093                loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "Meta-layer %s component layer %s adding instance extension %s",
2094                           prop->info.layerName, prop->component_layer_names.list[comp_layer],
2095                           comp_prop->instance_extension_list.list[ext].extensionName);
2096
2097                if (!has_vk_extension_property(&comp_prop->instance_extension_list.list[ext], &prop->instance_extension_list)) {
2098                    res = loader_add_to_ext_list(inst, &prop->instance_extension_list, 1,
2099                                                 &comp_prop->instance_extension_list.list[ext]);
2100                    if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
2101                        return res;
2102                    }
2103                }
2104            }
2105        }
2106        if (NULL != comp_prop->device_extension_list.list) {
2107            for (uint32_t ext = 0; ext < comp_prop->device_extension_list.count; ext++) {
2108                loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "Meta-layer %s component layer %s adding device extension %s",
2109                           prop->info.layerName, prop->component_layer_names.list[comp_layer],
2110                           comp_prop->device_extension_list.list[ext].props.extensionName);
2111
2112                if (!has_vk_dev_ext_property(&comp_prop->device_extension_list.list[ext].props, &prop->device_extension_list)) {
2113                    loader_add_to_dev_ext_list(inst, &prop->device_extension_list,
2114                                               &comp_prop->device_extension_list.list[ext].props, NULL);
2115                    if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
2116                        return res;
2117                    }
2118                }
2119            }
2120        }
2121    }
2122    return res;
2123}
2124
2125// Verify that all meta-layers in a layer list are valid.
2126VkResult verify_all_meta_layers(struct loader_instance *inst, const struct loader_envvar_all_filters *filters,
2127                                struct loader_layer_list *instance_layers, bool *override_layer_present) {
2128    VkResult res = VK_SUCCESS;
2129    *override_layer_present = false;
2130    for (int32_t i = 0; i < (int32_t)instance_layers->count; i++) {
2131        struct loader_layer_properties *prop = &instance_layers->list[i];
2132
2133        // If this is a meta-layer, make sure it is valid
2134        if (prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER) {
2135            if (verify_meta_layer_component_layers(inst, prop, instance_layers)) {
2136                // If any meta layer is valid, update its extension list to include the extensions from its component layers.
2137                res = update_meta_layer_extensions_from_component_layers(inst, prop, instance_layers);
2138                if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
2139                    return res;
2140                }
2141                if (prop->is_override && loader_implicit_layer_is_enabled(inst, filters, prop)) {
2142                    *override_layer_present = true;
2143                }
2144            } else {
2145                loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0,
2146                           "Removing meta-layer %s from instance layer list since it appears invalid.", prop->info.layerName);
2147
2148                loader_remove_layer_in_list(inst, instance_layers, i);
2149                i--;
2150            }
2151        }
2152    }
2153    return res;
2154}
2155
2156// If the current working directory matches any app_key_path of the layers, remove all other override layers.
2157// Otherwise if no matching app_key was found, remove all but the global override layer, which has no app_key_path.
2158void remove_all_non_valid_override_layers(struct loader_instance *inst, struct loader_layer_list *instance_layers) {
2159    if (instance_layers == NULL) {
2160        return;
2161    }
2162
2163    char cur_path[1024];
2164    char *ret = loader_platform_executable_path(cur_path, 1024);
2165    if (NULL == ret) {
2166        return;
2167    }
2168    // Find out if there is an override layer with same the app_key_path as the path to the current executable.
2169    // If more than one is found, remove it and use the first layer
2170    // Remove any layers which aren't global and do not have the same app_key_path as the path to the current executable.
2171    bool found_active_override_layer = false;
2172    int global_layer_index = -1;
2173    for (uint32_t i = 0; i < instance_layers->count; i++) {
2174        struct loader_layer_properties *props = &instance_layers->list[i];
2175        if (strcmp(props->info.layerName, VK_OVERRIDE_LAYER_NAME) == 0) {
2176            if (props->app_key_paths.count > 0) {  // not the global layer
2177                for (uint32_t j = 0; j < props->app_key_paths.count; j++) {
2178                    if (strcmp(props->app_key_paths.list[j], cur_path) == 0) {
2179                        if (!found_active_override_layer) {
2180                            found_active_override_layer = true;
2181                        } else {
2182                            loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
2183                                       "remove_all_non_valid_override_layers: Multiple override layers where the same path in "
2184                                       "app_keys "
2185                                       "was found. Using the first layer found");
2186
2187                            // Remove duplicate active override layers that have the same app_key_path
2188                            loader_remove_layer_in_list(inst, instance_layers, i);
2189                            i--;
2190                        }
2191                    }
2192                }
2193                if (!found_active_override_layer) {
2194                    loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_LAYER_BIT, 0,
2195                               "--Override layer found but not used because app \'%s\' is not in \'app_keys\' list!", cur_path);
2196
2197                    // Remove non-global override layers that don't have an app_key that matches cur_path
2198                    loader_remove_layer_in_list(inst, instance_layers, i);
2199                    i--;
2200                }
2201            } else {
2202                if (global_layer_index == -1) {
2203                    global_layer_index = i;
2204                } else {
2205                    loader_log(
2206                        inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
2207                        "remove_all_non_valid_override_layers: Multiple global override layers found. Using the first global "
2208                        "layer found");
2209                    loader_remove_layer_in_list(inst, instance_layers, i);
2210                    i--;
2211                }
2212            }
2213        }
2214    }
2215    // Remove global layer if layer with same the app_key_path as the path to the current executable is found
2216    if (found_active_override_layer && global_layer_index >= 0) {
2217        loader_remove_layer_in_list(inst, instance_layers, global_layer_index);
2218    }
2219    // Should be at most 1 override layer in the list now.
2220    if (found_active_override_layer) {
2221        loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_LAYER_BIT, 0, "Using the override layer for app key %s", cur_path);
2222    } else if (global_layer_index >= 0) {
2223        loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_LAYER_BIT, 0, "Using the global override layer");
2224    }
2225}
2226
2227/* The following are required in the "layer" object:
2228 * "name"
2229 * "type"
2230 * (for non-meta layers) "library_path"
2231 * (for meta layers) "component_layers"
2232 * "api_version"
2233 * "implementation_version"
2234 * "description"
2235 * (for implicit layers) "disable_environment"
2236 */
2237
2238VkResult loader_read_layer_json(const struct loader_instance *inst, struct loader_layer_list *layer_instance_list,
2239                                cJSON *layer_node, loader_api_version version, bool is_implicit, char *filename) {
2240    assert(layer_instance_list);
2241    char *type = NULL;
2242    char *api_version = NULL;
2243    char *implementation_version = NULL;
2244    VkResult result = VK_SUCCESS;
2245    struct loader_layer_properties props = {0};
2246
2247    // Parse name
2248
2249    result = loader_parse_json_string_to_existing_str(inst, layer_node, "name", VK_MAX_EXTENSION_NAME_SIZE, props.info.layerName);
2250    if (VK_ERROR_OUT_OF_HOST_MEMORY == result) goto out;
2251    if (VK_ERROR_INITIALIZATION_FAILED == result) {
2252        loader_log(inst, VULKAN_LOADER_WARN_BIT, 0,
2253                   "Layer located at %s didn't find required layer value \"name\" in manifest JSON file, skipping this layer",
2254                   filename);
2255        goto out;
2256    }
2257
2258    // Check if this layer's name matches the override layer name, set is_override to true if so.
2259    if (!strcmp(props.info.layerName, VK_OVERRIDE_LAYER_NAME)) {
2260        props.is_override = true;
2261    }
2262
2263    if (0 != strncmp(props.info.layerName, "VK_LAYER_", 9)) {
2264        loader_log(inst, VULKAN_LOADER_WARN_BIT, 0, "Layer name %s does not conform to naming standard (Policy #LLP_LAYER_3)",
2265                   props.info.layerName);
2266    }
2267
2268    // Parse type
2269
2270    result = loader_parse_json_string(layer_node, "type", &type);
2271    if (VK_ERROR_OUT_OF_HOST_MEMORY == result) goto out;
2272    if (VK_ERROR_INITIALIZATION_FAILED == result) {
2273        loader_log(inst, VULKAN_LOADER_WARN_BIT, 0,
2274                   "Layer located at %s didn't find required layer value \"type\" in manifest JSON file, skipping this layer",
2275                   filename);
2276        goto out;
2277    }
2278
2279    // Add list entry
2280    if (!strcmp(type, "DEVICE")) {
2281        loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0, "Device layers are deprecated. Skipping this layer");
2282        result = VK_ERROR_INITIALIZATION_FAILED;
2283        goto out;
2284    }
2285
2286    // Allow either GLOBAL or INSTANCE type interchangeably to handle layers that must work with older loaders
2287    if (!strcmp(type, "INSTANCE") || !strcmp(type, "GLOBAL")) {
2288        props.type_flags = VK_LAYER_TYPE_FLAG_INSTANCE_LAYER;
2289        if (!is_implicit) {
2290            props.type_flags |= VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER;
2291        }
2292    } else {
2293        result = VK_ERROR_INITIALIZATION_FAILED;
2294        goto out;
2295    }
2296
2297    // Parse api_version
2298
2299    result = loader_parse_json_string(layer_node, "api_version", &api_version);
2300    if (VK_ERROR_OUT_OF_HOST_MEMORY == result) goto out;
2301    if (VK_ERROR_INITIALIZATION_FAILED == result) {
2302        loader_log(
2303            inst, VULKAN_LOADER_WARN_BIT, 0,
2304            "Layer located at %s didn't find required layer value \"api_version\" in manifest JSON file, skipping this layer",
2305            filename);
2306        goto out;
2307    }
2308
2309    props.info.specVersion = loader_parse_version_string(api_version);
2310
2311    // Make sure the layer's manifest doesn't contain a non zero variant value
2312    if (VK_API_VERSION_VARIANT(props.info.specVersion) != 0) {
2313        loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_LAYER_BIT, 0,
2314                   "Layer \"%s\" has an \'api_version\' field which contains a non-zero variant value of %d. "
2315                   " Skipping Layer.",
2316                   props.info.layerName, VK_API_VERSION_VARIANT(props.info.specVersion));
2317        result = VK_ERROR_INITIALIZATION_FAILED;
2318        goto out;
2319    }
2320
2321    // Parse implementation_version
2322
2323    result = loader_parse_json_string(layer_node, "implementation_version", &implementation_version);
2324    if (VK_ERROR_OUT_OF_HOST_MEMORY == result) goto out;
2325    if (VK_ERROR_INITIALIZATION_FAILED == result) {
2326        loader_log(inst, VULKAN_LOADER_WARN_BIT, 0,
2327                   "Layer located at %s didn't find required layer value \"implementation_version\" in manifest JSON file, "
2328                   "skipping this layer",
2329                   filename);
2330        goto out;
2331    }
2332    props.info.implementationVersion = atoi(implementation_version);
2333
2334    // Parse description
2335
2336    result = loader_parse_json_string_to_existing_str(inst, layer_node, "description", VK_MAX_EXTENSION_NAME_SIZE,
2337                                                      props.info.description);
2338    if (VK_ERROR_OUT_OF_HOST_MEMORY == result) goto out;
2339    if (VK_ERROR_INITIALIZATION_FAILED == result) {
2340        loader_log(
2341            inst, VULKAN_LOADER_WARN_BIT, 0,
2342            "Layer located at %s didn't find required layer value \"description\" in manifest JSON file, skipping this layer",
2343            filename);
2344        goto out;
2345    }
2346
2347    // Parse library_path
2348
2349    // Library path no longer required unless component_layers is also not defined
2350    cJSON *library_path = loader_cJSON_GetObjectItem(layer_node, "library_path");
2351
2352    if (NULL != library_path) {
2353        if (NULL != loader_cJSON_GetObjectItem(layer_node, "component_layers")) {
2354            loader_log(inst, VULKAN_LOADER_WARN_BIT, 0,
2355                       "Indicating meta-layer-specific component_layers, but also defining layer library path.  Both are not "
2356                       "compatible, so skipping this layer");
2357            result = VK_ERROR_INITIALIZATION_FAILED;
2358            goto out;
2359        }
2360
2361        result = loader_copy_to_new_str(inst, filename, &props.manifest_file_name);
2362        if (result == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
2363
2364        char *library_path_str = loader_cJSON_Print(library_path);
2365        if (NULL == library_path_str) {
2366            loader_log(inst, VULKAN_LOADER_WARN_BIT, 0,
2367                       "Skipping layer due to problem accessing the library_path value in manifest JSON file %s", filename);
2368            result = VK_ERROR_OUT_OF_HOST_MEMORY;
2369            goto out;
2370        }
2371
2372        // This function takes ownership of library_path_str - so we don't need to clean it up
2373        result = combine_manifest_directory_and_library_path(inst, library_path_str, filename, &props.lib_name);
2374        if (result == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
2375    }
2376
2377    // Parse component_layers
2378
2379    if (NULL == library_path) {
2380        if (!loader_check_version_meets_required(LOADER_VERSION_1_1_0, version)) {
2381            loader_log(inst, VULKAN_LOADER_WARN_BIT, 0,
2382                       "Indicating meta-layer-specific component_layers, but using older JSON file version.");
2383        }
2384
2385        result = loader_parse_json_array_of_strings(inst, layer_node, "component_layers", &(props.component_layer_names));
2386        if (VK_ERROR_OUT_OF_HOST_MEMORY == result) {
2387            goto out;
2388        }
2389        if (VK_ERROR_INITIALIZATION_FAILED == result) {
2390            loader_log(inst, VULKAN_LOADER_WARN_BIT, 0,
2391                       "Layer missing both library_path and component_layers fields.  One or the other MUST be defined.  Skipping "
2392                       "this layer");
2393            goto out;
2394        }
2395        // This is now, officially, a meta-layer
2396        props.type_flags |= VK_LAYER_TYPE_FLAG_META_LAYER;
2397        loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_LAYER_BIT, 0, "Encountered meta-layer \"%s\"",
2398                   props.info.layerName);
2399    }
2400
2401    // Parse blacklisted_layers
2402
2403    if (props.is_override) {
2404        result = loader_parse_json_array_of_strings(inst, layer_node, "blacklisted_layers", &(props.blacklist_layer_names));
2405        if (VK_ERROR_OUT_OF_HOST_MEMORY == result) {
2406            goto out;
2407        }
2408    }
2409
2410    // Parse override_paths
2411
2412    result = loader_parse_json_array_of_strings(inst, layer_node, "override_paths", &(props.override_paths));
2413    if (VK_ERROR_OUT_OF_HOST_MEMORY == result) {
2414        goto out;
2415    }
2416    if (NULL != props.override_paths.list && !loader_check_version_meets_required(loader_combine_version(1, 1, 0), version)) {
2417        loader_log(inst, VULKAN_LOADER_WARN_BIT, 0,
2418                   "Indicating meta-layer-specific override paths, but using older JSON file version.");
2419    }
2420
2421    // Parse disable_environment
2422
2423    if (is_implicit) {
2424        cJSON *disable_environment = loader_cJSON_GetObjectItem(layer_node, "disable_environment");
2425        if (disable_environment == NULL) {
2426            loader_log(inst, VULKAN_LOADER_WARN_BIT, 0,
2427                       "Didn't find required layer object disable_environment in manifest JSON file, skipping this layer");
2428            result = VK_ERROR_INITIALIZATION_FAILED;
2429            goto out;
2430        }
2431
2432        if (!disable_environment->child || disable_environment->child->type != cJSON_String) {
2433            loader_log(inst, VULKAN_LOADER_WARN_BIT, 0,
2434                       "Didn't find required layer child value disable_environment in manifest JSON file, skipping this layer "
2435                       "(Policy #LLP_LAYER_9)");
2436            result = VK_ERROR_INITIALIZATION_FAILED;
2437            goto out;
2438        }
2439        result = loader_copy_to_new_str(inst, disable_environment->child->string, &(props.disable_env_var.name));
2440        if (VK_SUCCESS != result) goto out;
2441        result = loader_copy_to_new_str(inst, disable_environment->child->valuestring, &(props.disable_env_var.value));
2442        if (VK_SUCCESS != result) goto out;
2443    }
2444
2445    // Now get all optional items and objects and put in list:
2446    // functions
2447    // instance_extensions
2448    // device_extensions
2449    // enable_environment (implicit layers only)
2450    // library_arch
2451
2452    // Layer interface functions
2453    //    vkGetInstanceProcAddr
2454    //    vkGetDeviceProcAddr
2455    //    vkNegotiateLoaderLayerInterfaceVersion (starting with JSON file 1.1.0)
2456    cJSON *functions = loader_cJSON_GetObjectItem(layer_node, "functions");
2457    if (functions != NULL) {
2458        if (loader_check_version_meets_required(loader_combine_version(1, 1, 0), version)) {
2459            result = loader_parse_json_string(functions, "vkNegotiateLoaderLayerInterfaceVersion",
2460                                              &props.functions.str_negotiate_interface);
2461            if (result == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
2462        }
2463        result = loader_parse_json_string(functions, "vkGetInstanceProcAddr", &props.functions.str_gipa);
2464        if (result == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
2465
2466        if (props.functions.str_gipa && loader_check_version_meets_required(loader_combine_version(1, 1, 0), version)) {
2467            loader_log(inst, VULKAN_LOADER_INFO_BIT, 0,
2468                       "Layer \"%s\" using deprecated \'vkGetInstanceProcAddr\' tag which was deprecated starting with JSON "
2469                       "file version 1.1.0. The new vkNegotiateLoaderLayerInterfaceVersion function is preferred, though for "
2470                       "compatibility reasons it may be desirable to continue using the deprecated tag.",
2471                       props.info.layerName);
2472        }
2473
2474        result = loader_parse_json_string(functions, "vkGetDeviceProcAddr", &props.functions.str_gdpa);
2475        if (result == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
2476
2477        if (props.functions.str_gdpa && loader_check_version_meets_required(loader_combine_version(1, 1, 0), version)) {
2478            loader_log(inst, VULKAN_LOADER_INFO_BIT, 0,
2479                       "Layer \"%s\" using deprecated \'vkGetDeviceProcAddr\' tag which was deprecated starting with JSON "
2480                       "file version 1.1.0. The new vkNegotiateLoaderLayerInterfaceVersion function is preferred, though for "
2481                       "compatibility reasons it may be desirable to continue using the deprecated tag.",
2482                       props.info.layerName);
2483        }
2484    }
2485
2486    // instance_extensions
2487    //   array of {
2488    //     name
2489    //     spec_version
2490    //   }
2491
2492    cJSON *instance_extensions = loader_cJSON_GetObjectItem(layer_node, "instance_extensions");
2493    if (instance_extensions != NULL) {
2494        int count = loader_cJSON_GetArraySize(instance_extensions);
2495        for (int i = 0; i < count; i++) {
2496            VkExtensionProperties ext_prop = {0};
2497            cJSON *ext_item = loader_cJSON_GetArrayItem(instance_extensions, i);
2498            result = loader_parse_json_string_to_existing_str(inst, ext_item, "name", VK_MAX_EXTENSION_NAME_SIZE,
2499                                                              ext_prop.extensionName);
2500            if (result == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
2501            if (result == VK_ERROR_INITIALIZATION_FAILED) continue;
2502            char *spec_version = NULL;
2503            result = loader_parse_json_string(ext_item, "spec_version", &spec_version);
2504            if (result == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
2505            if (NULL != spec_version) {
2506                ext_prop.specVersion = atoi(spec_version);
2507            }
2508            loader_instance_heap_free(inst, spec_version);
2509            bool ext_unsupported = wsi_unsupported_instance_extension(&ext_prop);
2510            if (!ext_unsupported) {
2511                loader_add_to_ext_list(inst, &props.instance_extension_list, 1, &ext_prop);
2512            }
2513        }
2514    }
2515
2516    // device_extensions
2517    //   array of {
2518    //     name
2519    //     spec_version
2520    //     entrypoints
2521    //   }
2522    cJSON *device_extensions = loader_cJSON_GetObjectItem(layer_node, "device_extensions");
2523    if (device_extensions != NULL) {
2524        int count = loader_cJSON_GetArraySize(device_extensions);
2525        for (int i = 0; i < count; i++) {
2526            VkExtensionProperties ext_prop = {0};
2527
2528            cJSON *ext_item = loader_cJSON_GetArrayItem(device_extensions, i);
2529
2530            result = loader_parse_json_string_to_existing_str(inst, ext_item, "name", VK_MAX_EXTENSION_NAME_SIZE,
2531                                                              ext_prop.extensionName);
2532            if (result == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
2533
2534            char *spec_version = NULL;
2535            result = loader_parse_json_string(ext_item, "spec_version", &spec_version);
2536            if (result == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
2537            if (NULL != spec_version) {
2538                ext_prop.specVersion = atoi(spec_version);
2539            }
2540            loader_instance_heap_free(inst, spec_version);
2541
2542            cJSON *entrypoints = loader_cJSON_GetObjectItem(ext_item, "entrypoints");
2543            if (entrypoints == NULL) {
2544                result = loader_add_to_dev_ext_list(inst, &props.device_extension_list, &ext_prop, NULL);
2545                if (result == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
2546                continue;
2547            }
2548
2549            struct loader_string_list entrys = {0};
2550            result = loader_parse_json_array_of_strings(inst, ext_item, "entrypoints", &entrys);
2551            if (result == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
2552            result = loader_add_to_dev_ext_list(inst, &props.device_extension_list, &ext_prop, &entrys);
2553            if (result == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
2554        }
2555    }
2556    if (is_implicit) {
2557        cJSON *enable_environment = loader_cJSON_GetObjectItem(layer_node, "enable_environment");
2558
2559        // enable_environment is optional
2560        if (enable_environment && enable_environment->child && enable_environment->child->type == cJSON_String) {
2561            result = loader_copy_to_new_str(inst, enable_environment->child->string, &(props.enable_env_var.name));
2562            if (VK_SUCCESS != result) goto out;
2563            result = loader_copy_to_new_str(inst, enable_environment->child->valuestring, &(props.enable_env_var.value));
2564            if (VK_SUCCESS != result) goto out;
2565        }
2566    }
2567
2568    // Read in the pre-instance stuff
2569    cJSON *pre_instance = loader_cJSON_GetObjectItem(layer_node, "pre_instance_functions");
2570    if (NULL != pre_instance) {
2571        // Supported versions started in 1.1.2, so anything newer
2572        if (!loader_check_version_meets_required(loader_combine_version(1, 1, 2), version)) {
2573            loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
2574                       "Found pre_instance_functions section in layer from \"%s\". This section is only valid in manifest version "
2575                       "1.1.2 or later. The section will be ignored",
2576                       filename);
2577        } else if (!is_implicit) {
2578            loader_log(inst, VULKAN_LOADER_WARN_BIT, 0,
2579                       "Found pre_instance_functions section in explicit layer from \"%s\". This section is only valid in implicit "
2580                       "layers. The section will be ignored",
2581                       filename);
2582        } else {
2583            result = loader_parse_json_string(pre_instance, "vkEnumerateInstanceExtensionProperties",
2584                                              &props.pre_instance_functions.enumerate_instance_extension_properties);
2585            if (result == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
2586
2587            result = loader_parse_json_string(pre_instance, "vkEnumerateInstanceLayerProperties",
2588                                              &props.pre_instance_functions.enumerate_instance_layer_properties);
2589            if (result == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
2590
2591            result = loader_parse_json_string(pre_instance, "vkEnumerateInstanceVersion",
2592                                              &props.pre_instance_functions.enumerate_instance_version);
2593            if (result == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
2594        }
2595    }
2596
2597    if (loader_cJSON_GetObjectItem(layer_node, "app_keys")) {
2598        if (!props.is_override) {
2599            loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
2600                       "Layer %s contains app_keys, but any app_keys can only be provided by the override meta layer. "
2601                       "These will be ignored.",
2602                       props.info.layerName);
2603        }
2604
2605        result = loader_parse_json_array_of_strings(inst, layer_node, "app_keys", &props.app_key_paths);
2606        if (result == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
2607    }
2608
2609    char *library_arch = NULL;
2610    result = loader_parse_json_string(layer_node, "library_arch", &library_arch);
2611    if (result == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
2612    if (library_arch != NULL) {
2613        if ((strncmp(library_arch, "32", 2) == 0 && sizeof(void *) != 4) ||
2614            (strncmp(library_arch, "64", 2) == 0 && sizeof(void *) != 8)) {
2615            loader_log(inst, VULKAN_LOADER_INFO_BIT, 0,
2616                       "Layer library architecture doesn't match the current running architecture, skipping this layer");
2617            loader_instance_heap_free(inst, library_arch);
2618            result = VK_ERROR_INITIALIZATION_FAILED;
2619            goto out;
2620        }
2621        loader_instance_heap_free(inst, library_arch);
2622    }
2623
2624    result = VK_SUCCESS;
2625
2626out:
2627    // Try to append the layer property
2628    if (VK_SUCCESS == result) {
2629        result = loader_append_layer_property(inst, layer_instance_list, &props);
2630    }
2631    // If appending fails - free all the memory allocated in it
2632    if (VK_SUCCESS != result) {
2633        loader_free_layer_properties(inst, &props);
2634    }
2635    loader_instance_heap_free(inst, type);
2636    loader_instance_heap_free(inst, api_version);
2637    loader_instance_heap_free(inst, implementation_version);
2638    return result;
2639}
2640
2641bool is_valid_layer_json_version(const loader_api_version *layer_json) {
2642    // Supported versions are: 1.0.0, 1.0.1, 1.1.0 - 1.1.2, and 1.2.0 - 1.2.1.
2643    if ((layer_json->major == 1 && layer_json->minor == 2 && layer_json->patch < 2) ||
2644        (layer_json->major == 1 && layer_json->minor == 1 && layer_json->patch < 3) ||
2645        (layer_json->major == 1 && layer_json->minor == 0 && layer_json->patch < 2)) {
2646        return true;
2647    }
2648    return false;
2649}
2650
2651// Given a cJSON struct (json) of the top level JSON object from layer manifest
2652// file, add entry to the layer_list. Fill out the layer_properties in this list
2653// entry from the input cJSON object.
2654//
2655// \returns
2656// void
2657// layer_list has a new entry and initialized accordingly.
2658// If the json input object does not have all the required fields no entry
2659// is added to the list.
2660VkResult loader_add_layer_properties(const struct loader_instance *inst, struct loader_layer_list *layer_instance_list, cJSON *json,
2661                                     bool is_implicit, char *filename) {
2662    // The following Fields in layer manifest file that are required:
2663    //   - "file_format_version"
2664    //   - If more than one "layer" object are used, then the "layers" array is
2665    //     required
2666    VkResult result = VK_ERROR_INITIALIZATION_FAILED;
2667    cJSON *item, *layers_node, *layer_node;
2668    loader_api_version json_version = {0, 0, 0};
2669    char *file_vers = NULL;
2670    // Make sure sure the top level json value is an object
2671    if (!json || json->type != 6) {
2672        goto out;
2673    }
2674    item = loader_cJSON_GetObjectItem(json, "file_format_version");
2675    if (item == NULL) {
2676        goto out;
2677    }
2678    file_vers = loader_cJSON_PrintUnformatted(item);
2679    if (NULL == file_vers) {
2680        result = VK_ERROR_OUT_OF_HOST_MEMORY;
2681        goto out;
2682    }
2683    loader_log(inst, VULKAN_LOADER_INFO_BIT, 0, "Found manifest file %s (file version %s)", filename, file_vers);
2684    // Get the major/minor/and patch as integers for easier comparison
2685    json_version = loader_make_full_version(loader_parse_version_string(file_vers));
2686
2687    if (!is_valid_layer_json_version(&json_version)) {
2688        loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_LAYER_BIT, 0,
2689                   "loader_add_layer_properties: %s has unknown layer manifest file version %d.%d.%d.  May cause errors.", filename,
2690                   json_version.major, json_version.minor, json_version.patch);
2691    }
2692
2693    // If "layers" is present, read in the array of layer objects
2694    layers_node = loader_cJSON_GetObjectItem(json, "layers");
2695    if (layers_node != NULL) {
2696        int numItems = loader_cJSON_GetArraySize(layers_node);
2697        // Supported versions started in 1.0.1, so anything newer
2698        if (!loader_check_version_meets_required(loader_combine_version(1, 0, 1), json_version)) {
2699            loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
2700                       "loader_add_layer_properties: \'layers\' tag not supported until file version 1.0.1, but %s is reporting "
2701                       "version %s",
2702                       filename, file_vers);
2703        }
2704        for (int curLayer = 0; curLayer < numItems; curLayer++) {
2705            layer_node = loader_cJSON_GetArrayItem(layers_node, curLayer);
2706            if (layer_node == NULL) {
2707                loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
2708                           "loader_add_layer_properties: Can not find 'layers' array element %d object in manifest JSON file %s.  "
2709                           "Skipping this file",
2710                           curLayer, filename);
2711                goto out;
2712            }
2713            result = loader_read_layer_json(inst, layer_instance_list, layer_node, json_version, is_implicit, filename);
2714        }
2715    } else {
2716        // Otherwise, try to read in individual layers
2717        layer_node = loader_cJSON_GetObjectItem(json, "layer");
2718        if (layer_node == NULL) {
2719            loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
2720                       "loader_add_layer_properties: Can not find 'layer' object in manifest JSON file %s.  Skipping this file.",
2721                       filename);
2722            goto out;
2723        }
2724        // Loop through all "layer" objects in the file to get a count of them
2725        // first.
2726        uint16_t layer_count = 0;
2727        cJSON *tempNode = layer_node;
2728        do {
2729            tempNode = tempNode->next;
2730            layer_count++;
2731        } while (tempNode != NULL);
2732
2733        // Throw a warning if we encounter multiple "layer" objects in file
2734        // versions newer than 1.0.0.  Having multiple objects with the same
2735        // name at the same level is actually a JSON standard violation.
2736        if (layer_count > 1 && loader_check_version_meets_required(loader_combine_version(1, 0, 1), json_version)) {
2737            loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_LAYER_BIT, 0,
2738                       "loader_add_layer_properties: Multiple 'layer' nodes are deprecated starting in file version \"1.0.1\".  "
2739                       "Please use 'layers' : [] array instead in %s.",
2740                       filename);
2741        } else {
2742            do {
2743                result = loader_read_layer_json(inst, layer_instance_list, layer_node, json_version, is_implicit, filename);
2744                layer_node = layer_node->next;
2745            } while (layer_node != NULL);
2746        }
2747    }
2748
2749out:
2750    loader_instance_heap_free(inst, file_vers);
2751
2752    return result;
2753}
2754
2755size_t determine_data_file_path_size(const char *cur_path, size_t relative_path_size) {
2756    size_t path_size = 0;
2757
2758    if (NULL != cur_path) {
2759        // For each folder in cur_path, (detected by finding additional
2760        // path separators in the string) we need to add the relative path on
2761        // the end.  Plus, leave an additional two slots on the end to add an
2762        // additional directory slash and path separator if needed
2763        path_size += strlen(cur_path) + relative_path_size + 2;
2764        for (const char *x = cur_path; *x; ++x) {
2765            if (*x == PATH_SEPARATOR) {
2766                path_size += relative_path_size + 2;
2767            }
2768        }
2769    }
2770
2771    return path_size;
2772}
2773
2774void copy_data_file_info(const char *cur_path, const char *relative_path, size_t relative_path_size, char **output_path) {
2775    if (NULL != cur_path) {
2776        uint32_t start = 0;
2777        uint32_t stop = 0;
2778        char *cur_write = *output_path;
2779
2780        while (cur_path[start] != '\0') {
2781            while (cur_path[start] == PATH_SEPARATOR) {
2782                start++;
2783            }
2784            stop = start;
2785            while (cur_path[stop] != PATH_SEPARATOR && cur_path[stop] != '\0') {
2786                stop++;
2787            }
2788            const size_t s = stop - start;
2789            if (s) {
2790                memcpy(cur_write, &cur_path[start], s);
2791                cur_write += s;
2792
2793                // If this is a specific JSON file, just add it and don't add any
2794                // relative path or directory symbol to it.
2795                if (!is_json(cur_write - 5, s)) {
2796                    // Add the relative directory if present.
2797                    if (relative_path_size > 0) {
2798                        // If last symbol written was not a directory symbol, add it.
2799                        if (*(cur_write - 1) != DIRECTORY_SYMBOL) {
2800                            *cur_write++ = DIRECTORY_SYMBOL;
2801                        }
2802                        memcpy(cur_write, relative_path, relative_path_size);
2803                        cur_write += relative_path_size;
2804                    }
2805                }
2806
2807                *cur_write++ = PATH_SEPARATOR;
2808                start = stop;
2809            }
2810        }
2811        *output_path = cur_write;
2812    }
2813}
2814
2815// If the file found is a manifest file name, add it to the out_files manifest list.
2816VkResult add_if_manifest_file(const struct loader_instance *inst, const char *file_name, struct loader_string_list *out_files) {
2817    VkResult vk_result = VK_SUCCESS;
2818
2819    assert(NULL != file_name && "add_if_manifest_file: Received NULL pointer for file_name");
2820    assert(NULL != out_files && "add_if_manifest_file: Received NULL pointer for out_files");
2821
2822    // Look for files ending with ".json" suffix
2823    size_t name_len = strlen(file_name);
2824    const char *name_suffix = file_name + name_len - 5;
2825    if (!is_json(name_suffix, name_len)) {
2826        // Use incomplete to indicate invalid name, but to keep going.
2827        vk_result = VK_INCOMPLETE;
2828        goto out;
2829    }
2830
2831    vk_result = copy_str_to_string_list(inst, out_files, file_name, name_len);
2832
2833out:
2834
2835    return vk_result;
2836}
2837
2838// Add any files found in the search_path.  If any path in the search path points to a specific JSON, attempt to
2839// only open that one JSON.  Otherwise, if the path is a folder, search the folder for JSON files.
2840VkResult add_data_files(const struct loader_instance *inst, char *search_path, struct loader_string_list *out_files,
2841                        bool use_first_found_manifest) {
2842    VkResult vk_result = VK_SUCCESS;
2843    DIR *dir_stream = NULL;
2844    struct dirent *dir_entry;
2845    char *cur_file;
2846    char *next_file;
2847    char *name;
2848    char full_path[2048];
2849#if !defined(_WIN32)
2850    char temp_path[2048];
2851#endif
2852
2853    // Now, parse the paths
2854    next_file = search_path;
2855    while (NULL != next_file && *next_file != '\0') {
2856        name = NULL;
2857        cur_file = next_file;
2858        next_file = loader_get_next_path(cur_file);
2859
2860        // Is this a JSON file, then try to open it.
2861        size_t len = strlen(cur_file);
2862        if (is_json(cur_file + len - 5, len)) {
2863#if defined(_WIN32)
2864            name = cur_file;
2865#elif COMMON_UNIX_PLATFORMS
2866            // Only Linux has relative paths, make a copy of location so it isn't modified
2867            size_t str_len;
2868            if (NULL != next_file) {
2869                str_len = next_file - cur_file + 1;
2870            } else {
2871                str_len = strlen(cur_file) + 1;
2872            }
2873            if (str_len > sizeof(temp_path)) {
2874                loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "add_data_files: Path to %s too long", cur_file);
2875                continue;
2876            }
2877            strncpy(temp_path, cur_file, str_len);
2878            name = temp_path;
2879#else
2880#warning add_data_files must define relative path copy for this platform
2881#endif
2882            loader_get_fullpath(cur_file, name, sizeof(full_path), full_path);
2883            name = full_path;
2884
2885            VkResult local_res;
2886            local_res = add_if_manifest_file(inst, name, out_files);
2887
2888            // Incomplete means this was not a valid data file.
2889            if (local_res == VK_INCOMPLETE) {
2890                continue;
2891            } else if (local_res != VK_SUCCESS) {
2892                vk_result = local_res;
2893                break;
2894            }
2895        } else {  // Otherwise, treat it as a directory
2896            dir_stream = loader_opendir(inst, cur_file);
2897            if (NULL == dir_stream) {
2898                continue;
2899            }
2900            while (1) {
2901                dir_entry = readdir(dir_stream);
2902                if (NULL == dir_entry) {
2903                    break;
2904                }
2905
2906                name = &(dir_entry->d_name[0]);
2907                loader_get_fullpath(name, cur_file, sizeof(full_path), full_path);
2908                name = full_path;
2909
2910                VkResult local_res;
2911                local_res = add_if_manifest_file(inst, name, out_files);
2912
2913                // Incomplete means this was not a valid data file.
2914                if (local_res == VK_INCOMPLETE) {
2915                    continue;
2916                } else if (local_res != VK_SUCCESS) {
2917                    vk_result = local_res;
2918                    break;
2919                }
2920            }
2921            loader_closedir(inst, dir_stream);
2922            if (vk_result != VK_SUCCESS) {
2923                goto out;
2924            }
2925        }
2926        if (use_first_found_manifest && out_files->count > 0) {
2927            break;
2928        }
2929    }
2930
2931out:
2932
2933    return vk_result;
2934}
2935
2936// Look for data files in the provided paths, but first check the environment override to determine if we should use that
2937// instead.
2938VkResult read_data_files_in_search_paths(const struct loader_instance *inst, enum loader_data_files_type manifest_type,
2939                                         const char *path_override, bool *override_active, struct loader_string_list *out_files) {
2940    VkResult vk_result = VK_SUCCESS;
2941    char *override_env = NULL;
2942    const char *override_path = NULL;
2943    char *additional_env = NULL;
2944    size_t search_path_size = 0;
2945    char *search_path = NULL;
2946    char *cur_path_ptr = NULL;
2947    bool use_first_found_manifest = false;
2948#if COMMON_UNIX_PLATFORMS
2949    char *relative_location = NULL;  // Only used on unix platforms
2950    size_t rel_size = 0;             // unused in windows, dont declare so no compiler warnings are generated
2951#endif
2952
2953#if defined(_WIN32)
2954    char *package_path = NULL;
2955#elif COMMON_UNIX_PLATFORMS
2956    // Determine how much space is needed to generate the full search path
2957    // for the current manifest files.
2958    char *xdg_config_home = loader_secure_getenv("XDG_CONFIG_HOME", inst);
2959    char *xdg_config_dirs = loader_secure_getenv("XDG_CONFIG_DIRS", inst);
2960
2961#if !defined(__Fuchsia__) && !defined(__QNX__) && !defined(__OHOS__)
2962    if (NULL == xdg_config_dirs || '\0' == xdg_config_dirs[0]) {
2963        xdg_config_dirs = FALLBACK_CONFIG_DIRS;
2964    }
2965#endif
2966
2967    char *xdg_data_home = loader_secure_getenv("XDG_DATA_HOME", inst);
2968    char *xdg_data_dirs = loader_secure_getenv("XDG_DATA_DIRS", inst);
2969
2970#if !defined(__Fuchsia__) && !defined(__QNX__) && !defined(__OHOS__)
2971    if (NULL == xdg_data_dirs || '\0' == xdg_data_dirs[0]) {
2972        xdg_data_dirs = FALLBACK_DATA_DIRS;
2973    }
2974#endif
2975
2976    char *home = NULL;
2977    char *default_data_home = NULL;
2978    char *default_config_home = NULL;
2979    char *home_data_dir = NULL;
2980    char *home_config_dir = NULL;
2981
2982    // Only use HOME if XDG_DATA_HOME is not present on the system
2983    home = loader_secure_getenv("HOME", inst);
2984    if (home != NULL) {
2985        if (NULL == xdg_config_home || '\0' == xdg_config_home[0]) {
2986            const char config_suffix[] = "/.config";
2987            size_t default_config_home_len = strlen(home) + sizeof(config_suffix) + 1;
2988            default_config_home = loader_instance_heap_calloc(inst, default_config_home_len, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
2989            if (default_config_home == NULL) {
2990                vk_result = VK_ERROR_OUT_OF_HOST_MEMORY;
2991                goto out;
2992            }
2993            strncpy(default_config_home, home, default_config_home_len);
2994            strncat(default_config_home, config_suffix, default_config_home_len);
2995        }
2996        if (NULL == xdg_data_home || '\0' == xdg_data_home[0]) {
2997            const char data_suffix[] = "/.local/share";
2998            size_t default_data_home_len = strlen(home) + sizeof(data_suffix) + 1;
2999            default_data_home = loader_instance_heap_calloc(inst, default_data_home_len, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
3000            if (default_data_home == NULL) {
3001                vk_result = VK_ERROR_OUT_OF_HOST_MEMORY;
3002                goto out;
3003            }
3004            strncpy(default_data_home, home, default_data_home_len);
3005            strncat(default_data_home, data_suffix, default_data_home_len);
3006        }
3007    }
3008
3009    if (NULL != default_config_home) {
3010        home_config_dir = default_config_home;
3011    } else {
3012        home_config_dir = xdg_config_home;
3013    }
3014    if (NULL != default_data_home) {
3015        home_data_dir = default_data_home;
3016    } else {
3017        home_data_dir = xdg_data_home;
3018    }
3019
3020#if defined(__OHOS__)
3021    char *debug_layer_name = loader_secure_getenv("debug.graphic.debug_layer", inst); // squid squidsubcapture
3022    char *debug_hap_name = loader_secure_getenv("debug.graphic.debug_hap", inst);
3023    char *debug_layer_json_path = NULL;
3024
3025    bool currentProcessEnableDebugLayer = false;
3026    if (NULL != debug_layer_name && '\0' != debug_layer_name[0] && InitBundleInfo(debug_hap_name)) {
3027        currentProcessEnableDebugLayer = true;
3028        debug_layer_json_path = loader_secure_getenv("debug.graphic.vklayer_json_path",inst);
3029        if (NULL == debug_layer_json_path || '\0' == debug_layer_json_path[0]){
3030            const char default_json_path[] = "/data/storage/el2/base/haps/entry/files/";
3031            const char json_suffix[] = ".json";
3032            size_t debug_layer_json_path_len = strlen(default_json_path) + sizeof(debug_layer_name) + sizeof(json_suffix) +1;
3033            debug_layer_json_path = loader_instance_heap_calloc(inst,debug_layer_json_path_len,VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
3034            if(debug_layer_json_path == NULL){
3035                vk_result = VK_ERROR_OUT_OF_HOST_MEMORY;
3036                goto out;
3037            }
3038            strncpy(debug_layer_json_path,default_json_path,debug_layer_json_path_len);
3039            strncat(debug_layer_json_path,debug_layer_name,debug_layer_json_path_len);
3040            strncat(debug_layer_json_path,json_suffix,debug_layer_json_path_len);
3041        }
3042        loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "OHOS:: debug_layer_json_path: %s", debug_layer_json_path);
3043    }
3044#endif
3045
3046#else
3047#warning read_data_files_in_search_paths unsupported platform
3048#endif
3049
3050    switch (manifest_type) {
3051        case LOADER_DATA_FILE_MANIFEST_DRIVER:
3052            override_env = loader_secure_getenv(VK_DRIVER_FILES_ENV_VAR, inst);
3053            if (NULL == override_env) {
3054                // Not there, so fall back to the old name
3055                override_env = loader_secure_getenv(VK_ICD_FILENAMES_ENV_VAR, inst);
3056            }
3057            additional_env = loader_secure_getenv(VK_ADDITIONAL_DRIVER_FILES_ENV_VAR, inst);
3058#if COMMON_UNIX_PLATFORMS
3059            relative_location = VK_DRIVERS_INFO_RELATIVE_DIR;
3060#endif
3061#if defined(_WIN32)
3062            package_path = windows_get_app_package_manifest_path(inst);
3063#endif
3064            break;
3065        case LOADER_DATA_FILE_MANIFEST_IMPLICIT_LAYER:
3066#if COMMON_UNIX_PLATFORMS
3067            relative_location = VK_ILAYERS_INFO_RELATIVE_DIR;
3068#endif
3069            break;
3070        case LOADER_DATA_FILE_MANIFEST_EXPLICIT_LAYER:
3071            override_env = loader_secure_getenv(VK_LAYER_PATH_ENV_VAR, inst);
3072            additional_env = loader_secure_getenv(VK_ADDITIONAL_LAYER_PATH_ENV_VAR, inst);
3073#if COMMON_UNIX_PLATFORMS
3074            relative_location = VK_ELAYERS_INFO_RELATIVE_DIR;
3075#endif
3076            break;
3077        default:
3078            assert(false && "Shouldn't get here!");
3079            break;
3080    }
3081
3082    // Log a message when VK_LAYER_PATH is set but the override layer paths take priority
3083    if (manifest_type == LOADER_DATA_FILE_MANIFEST_EXPLICIT_LAYER && NULL != override_env && NULL != path_override) {
3084        loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_LAYER_BIT, 0,
3085                   "Ignoring VK_LAYER_PATH. The Override layer is active and has override paths set, which takes priority. "
3086                   "VK_LAYER_PATH is set to %s",
3087                   override_env);
3088    }
3089
3090    if (path_override != NULL) {
3091        override_path = path_override;
3092    } else if (override_env != NULL) {
3093        override_path = override_env;
3094    }
3095
3096    // Add two by default for NULL terminator and one path separator on end (just in case)
3097    search_path_size = 2;
3098
3099    // If there's an override, use that (and the local folder if required) and nothing else
3100    if (NULL != override_path) {
3101        // Local folder and null terminator
3102        search_path_size += strlen(override_path) + 2;
3103    } else {
3104        // Add the size of any additional search paths defined in the additive environment variable
3105        if (NULL != additional_env) {
3106            search_path_size += determine_data_file_path_size(additional_env, 0) + 2;
3107#if defined(_WIN32)
3108        }
3109        if (NULL != package_path) {
3110            search_path_size += determine_data_file_path_size(package_path, 0) + 2;
3111        }
3112        if (search_path_size == 2) {
3113            goto out;
3114        }
3115#elif COMMON_UNIX_PLATFORMS
3116        }
3117
3118        // Add the general search folders (with the appropriate relative folder added)
3119        rel_size = strlen(relative_location);
3120        if (rel_size > 0) {
3121#if defined(__APPLE__)
3122            search_path_size += MAXPATHLEN;
3123#endif
3124            // Only add the home folders if defined
3125            if (NULL != home_config_dir) {
3126                search_path_size += determine_data_file_path_size(home_config_dir, rel_size);
3127            }
3128            search_path_size += determine_data_file_path_size(xdg_config_dirs, rel_size);
3129            search_path_size += determine_data_file_path_size(SYSCONFDIR, rel_size);
3130#if defined(EXTRASYSCONFDIR)
3131            search_path_size += determine_data_file_path_size(EXTRASYSCONFDIR, rel_size);
3132#endif
3133            // Only add the home folders if defined
3134            if (NULL != home_data_dir) {
3135                search_path_size += determine_data_file_path_size(home_data_dir, rel_size);
3136            }
3137            search_path_size += determine_data_file_path_size(xdg_data_dirs, rel_size);
3138#if defined (__OHOS__)
3139            if(currentProcessEnableDebugLayer) {
3140                search_path_size += determine_data_file_path_size(debug_layer_json_path, rel_size);
3141            }
3142            search_path_size += determine_data_file_path_size("/system/etc/vulkan/swapchain", rel_size);
3143#endif
3144        }
3145#else
3146#warning read_data_files_in_search_paths unsupported platform
3147#endif
3148    }
3149
3150    // Allocate the required space
3151    search_path = loader_instance_heap_calloc(inst, search_path_size, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
3152    if (NULL == search_path) {
3153        loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
3154                   "read_data_files_in_search_paths: Failed to allocate space for search path of length %d",
3155                   (uint32_t)search_path_size);
3156        vk_result = VK_ERROR_OUT_OF_HOST_MEMORY;
3157        goto out;
3158    }
3159
3160    cur_path_ptr = search_path;
3161
3162    // Add the remaining paths to the list
3163    if (NULL != override_path) {
3164        size_t override_path_len = strlen(override_path);
3165        loader_strncpy(cur_path_ptr, search_path_size, override_path, override_path_len);
3166        cur_path_ptr += override_path_len;
3167    } else {
3168        // Add any additional search paths defined in the additive environment variable
3169        if (NULL != additional_env) {
3170            copy_data_file_info(additional_env, NULL, 0, &cur_path_ptr);
3171        }
3172
3173#if defined(_WIN32)
3174        if (NULL != package_path) {
3175            copy_data_file_info(package_path, NULL, 0, &cur_path_ptr);
3176        }
3177#elif COMMON_UNIX_PLATFORMS
3178        if (rel_size > 0) {
3179#if defined(__APPLE__)
3180            // Add the bundle's Resources dir to the beginning of the search path.
3181            // Looks for manifests in the bundle first, before any system directories.
3182            // This also appears to work unmodified for iOS, it finds the app bundle on the devices
3183            // file system. (RSW)
3184            CFBundleRef main_bundle = CFBundleGetMainBundle();
3185            if (NULL != main_bundle) {
3186                CFURLRef ref = CFBundleCopyResourcesDirectoryURL(main_bundle);
3187                if (NULL != ref) {
3188                    if (CFURLGetFileSystemRepresentation(ref, TRUE, (UInt8 *)cur_path_ptr, search_path_size)) {
3189                        cur_path_ptr += strlen(cur_path_ptr);
3190                        *cur_path_ptr++ = DIRECTORY_SYMBOL;
3191                        memcpy(cur_path_ptr, relative_location, rel_size);
3192                        cur_path_ptr += rel_size;
3193                        *cur_path_ptr++ = PATH_SEPARATOR;
3194                        if (manifest_type == LOADER_DATA_FILE_MANIFEST_DRIVER) {
3195                            use_first_found_manifest = true;
3196                        }
3197                    }
3198                    CFRelease(ref);
3199                }
3200            }
3201#endif  // __APPLE__
3202
3203            // Only add the home folders if not NULL
3204            if (NULL != home_config_dir) {
3205                copy_data_file_info(home_config_dir, relative_location, rel_size, &cur_path_ptr);
3206            }
3207            copy_data_file_info(xdg_config_dirs, relative_location, rel_size, &cur_path_ptr);
3208            copy_data_file_info(SYSCONFDIR, relative_location, rel_size, &cur_path_ptr);
3209#if defined(EXTRASYSCONFDIR)
3210            copy_data_file_info(EXTRASYSCONFDIR, relative_location, rel_size, &cur_path_ptr);
3211#endif
3212
3213            // Only add the home folders if not NULL
3214            if (NULL != home_data_dir) {
3215                copy_data_file_info(home_data_dir, relative_location, rel_size, &cur_path_ptr);
3216            }
3217            copy_data_file_info(xdg_data_dirs, relative_location, rel_size, &cur_path_ptr);
3218#if defined (__OHOS__)
3219            if(currentProcessEnableDebugLayer){
3220                copy_data_file_info(debug_layer_json_path,relative_location,rel_size,&cur_path_ptr);
3221            }
3222            copy_data_file_info("/system/etc/vulkan/swapchain/",relative_location,rel_size,&cur_path_ptr);
3223#endif
3224        }
3225
3226        // Remove the last path separator
3227        --cur_path_ptr;
3228
3229        assert(cur_path_ptr - search_path < (ptrdiff_t)search_path_size);
3230        *cur_path_ptr = '\0';
3231#else
3232#warning read_data_files_in_search_paths unsupported platform
3233#endif
3234    }
3235
3236    // Remove duplicate paths, or it would result in duplicate extensions, duplicate devices, etc.
3237    // This uses minimal memory, but is O(N^2) on the number of paths. Expect only a few paths.
3238    char path_sep_str[2] = {PATH_SEPARATOR, '\0'};
3239    size_t search_path_updated_size = strlen(search_path);
3240    for (size_t first = 0; first < search_path_updated_size;) {
3241        // If this is an empty path, erase it
3242        if (search_path[first] == PATH_SEPARATOR) {
3243            memmove(&search_path[first], &search_path[first + 1], search_path_updated_size - first + 1);
3244            search_path_updated_size -= 1;
3245            continue;
3246        }
3247
3248        size_t first_end = first + 1;
3249        first_end += strcspn(&search_path[first_end], path_sep_str);
3250        for (size_t second = first_end + 1; second < search_path_updated_size;) {
3251            size_t second_end = second + 1;
3252            second_end += strcspn(&search_path[second_end], path_sep_str);
3253            if (first_end - first == second_end - second &&
3254                !strncmp(&search_path[first], &search_path[second], second_end - second)) {
3255                // Found duplicate. Include PATH_SEPARATOR in second_end, then erase it from search_path.
3256                if (search_path[second_end] == PATH_SEPARATOR) {
3257                    second_end++;
3258                }
3259                memmove(&search_path[second], &search_path[second_end], search_path_updated_size - second_end + 1);
3260                search_path_updated_size -= second_end - second;
3261            } else {
3262                second = second_end + 1;
3263            }
3264        }
3265        first = first_end + 1;
3266    }
3267    search_path_size = search_path_updated_size;
3268
3269    // Print out the paths being searched if debugging is enabled
3270    uint32_t log_flags = 0;
3271    if (search_path_size > 0) {
3272        char *tmp_search_path = loader_instance_heap_alloc(inst, search_path_size + 1, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
3273        if (NULL != tmp_search_path) {
3274            loader_strncpy(tmp_search_path, search_path_size + 1, search_path, search_path_size);
3275            tmp_search_path[search_path_size] = '\0';
3276            if (manifest_type == LOADER_DATA_FILE_MANIFEST_DRIVER) {
3277                log_flags = VULKAN_LOADER_DRIVER_BIT;
3278                loader_log(inst, VULKAN_LOADER_DRIVER_BIT, 0, "Searching for driver manifest files");
3279            } else {
3280                log_flags = VULKAN_LOADER_LAYER_BIT;
3281                loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, "Searching for %s layer manifest files",
3282                           manifest_type == LOADER_DATA_FILE_MANIFEST_EXPLICIT_LAYER ? "explicit" : "implicit");
3283            }
3284            loader_log(inst, log_flags, 0, "   In following locations:");
3285            char *cur_file;
3286            char *next_file = tmp_search_path;
3287            while (NULL != next_file && *next_file != '\0') {
3288                cur_file = next_file;
3289                next_file = loader_get_next_path(cur_file);
3290                loader_log(inst, log_flags, 0, "      %s", cur_file);
3291            }
3292            loader_instance_heap_free(inst, tmp_search_path);
3293        }
3294    }
3295
3296    // Now, parse the paths and add any manifest files found in them.
3297    vk_result = add_data_files(inst, search_path, out_files, use_first_found_manifest);
3298
3299    if (log_flags != 0 && out_files->count > 0) {
3300        loader_log(inst, log_flags, 0, "   Found the following files:");
3301        for (uint32_t cur_file = 0; cur_file < out_files->count; ++cur_file) {
3302            loader_log(inst, log_flags, 0, "      %s", out_files->list[cur_file]);
3303        }
3304    } else {
3305        loader_log(inst, log_flags, 0, "   Found no files");
3306    }
3307
3308    if (NULL != override_path) {
3309        *override_active = true;
3310    } else {
3311        *override_active = false;
3312    }
3313
3314out:
3315
3316    loader_free_getenv(additional_env, inst);
3317    loader_free_getenv(override_env, inst);
3318#if defined(_WIN32)
3319    loader_instance_heap_free(inst, package_path);
3320#elif COMMON_UNIX_PLATFORMS
3321    loader_free_getenv(xdg_config_home, inst);
3322    loader_free_getenv(xdg_config_dirs, inst);
3323    loader_free_getenv(xdg_data_home, inst);
3324    loader_free_getenv(xdg_data_dirs, inst);
3325    loader_free_getenv(xdg_data_home, inst);
3326    loader_free_getenv(home, inst);
3327    loader_instance_heap_free(inst, default_data_home);
3328    loader_instance_heap_free(inst, default_config_home);
3329#elif defined(__OHOS__)
3330    if(currentProcessEnableDebugLayer){
3331        loader_free_getenv(debug_layer_json_path, inst);
3332    }
3333    loader_free_getenv(debug_layer_name, inst);
3334    loader_free_getenv(debug_hap_name, inst);
3335#else
3336#warning read_data_files_in_search_paths unsupported platform
3337#endif
3338
3339    loader_instance_heap_free(inst, search_path);
3340
3341    return vk_result;
3342}
3343
3344// Find the Vulkan library manifest files.
3345//
3346// This function scans the appropriate locations for a list of JSON manifest files based on the
3347// "manifest_type".  The location is interpreted as Registry path on Windows and a directory path(s)
3348// on Linux.
3349// "home_location" is an additional directory in the users home directory to look at. It is
3350// expanded into the dir path $XDG_DATA_HOME/home_location or $HOME/.local/share/home_location
3351// depending on environment variables. This "home_location" is only used on Linux.
3352//
3353// \returns
3354// VKResult
3355// A string list of manifest files to be opened in out_files param.
3356// List has a pointer to string for each manifest filename.
3357// When done using the list in out_files, pointers should be freed.
3358// Location or override  string lists can be either files or directories as
3359// follows:
3360//            | location | override
3361// --------------------------------
3362// Win ICD    | files    | files
3363// Win Layer  | files    | dirs
3364// Linux ICD  | dirs     | files
3365// Linux Layer| dirs     | dirs
3366
3367VkResult loader_get_data_files(const struct loader_instance *inst, enum loader_data_files_type manifest_type,
3368                               const char *path_override, struct loader_string_list *out_files) {
3369    VkResult res = VK_SUCCESS;
3370    bool override_active = false;
3371
3372    // Free and init the out_files information so there's no false data left from uninitialized variables.
3373    free_string_list(inst, out_files);
3374
3375    res = read_data_files_in_search_paths(inst, manifest_type, path_override, &override_active, out_files);
3376    if (VK_SUCCESS != res) {
3377        goto out;
3378    }
3379
3380#if defined(_WIN32)
3381    // Read the registry if the override wasn't active.
3382    if (!override_active) {
3383        bool warn_if_not_present = false;
3384        char *registry_location = NULL;
3385
3386        switch (manifest_type) {
3387            default:
3388                goto out;
3389            case LOADER_DATA_FILE_MANIFEST_DRIVER:
3390                warn_if_not_present = true;
3391                registry_location = VK_DRIVERS_INFO_REGISTRY_LOC;
3392                break;
3393            case LOADER_DATA_FILE_MANIFEST_IMPLICIT_LAYER:
3394                registry_location = VK_ILAYERS_INFO_REGISTRY_LOC;
3395                break;
3396            case LOADER_DATA_FILE_MANIFEST_EXPLICIT_LAYER:
3397                warn_if_not_present = true;
3398                registry_location = VK_ELAYERS_INFO_REGISTRY_LOC;
3399                break;
3400        }
3401        VkResult tmp_res =
3402            windows_read_data_files_in_registry(inst, manifest_type, warn_if_not_present, registry_location, out_files);
3403        // Only return an error if there was an error this time, and no manifest files from before.
3404        if (VK_SUCCESS != tmp_res && out_files->count == 0) {
3405            res = tmp_res;
3406            goto out;
3407        }
3408    }
3409#endif
3410
3411out:
3412
3413    if (VK_SUCCESS != res) {
3414        free_string_list(inst, out_files);
3415    }
3416
3417    return res;
3418}
3419
3420struct ICDManifestInfo {
3421    char *full_library_path;
3422    uint32_t version;
3423};
3424
3425// Takes a json file, opens, reads, and parses an ICD Manifest out of it.
3426// Should only return VK_SUCCESS, VK_ERROR_INCOMPATIBLE_DRIVER, or VK_ERROR_OUT_OF_HOST_MEMORY
3427VkResult loader_parse_icd_manifest(const struct loader_instance *inst, char *file_str, struct ICDManifestInfo *icd,
3428                                   bool *skipped_portability_drivers) {
3429    VkResult res = VK_SUCCESS;
3430    cJSON *json = NULL;
3431    char *file_vers_str = NULL;
3432    char *library_arch_str = NULL;
3433    char *version_str = NULL;
3434
3435    if (file_str == NULL) {
3436        goto out;
3437    }
3438
3439    res = loader_get_json(inst, file_str, &json);
3440    if (res == VK_ERROR_OUT_OF_HOST_MEMORY) {
3441        goto out;
3442    }
3443    if (res != VK_SUCCESS || NULL == json) {
3444        res = VK_ERROR_INCOMPATIBLE_DRIVER;
3445        goto out;
3446    }
3447
3448    cJSON *item = loader_cJSON_GetObjectItem(json, "file_format_version");
3449    if (item == NULL) {
3450        loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
3451                   "loader_parse_icd_manifest: ICD JSON %s does not have a \'file_format_version\' field. Skipping ICD JSON.",
3452                   file_str);
3453        res = VK_ERROR_INCOMPATIBLE_DRIVER;
3454        goto out;
3455    }
3456
3457    file_vers_str = loader_cJSON_Print(item);
3458    if (NULL == file_vers_str) {
3459        // Only reason the print can fail is if there was an allocation issue
3460        loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
3461                   "loader_parse_icd_manifest: Failed retrieving ICD JSON %s \'file_format_version\' field. Skipping ICD JSON",
3462                   file_str);
3463        res = VK_ERROR_OUT_OF_HOST_MEMORY;
3464        goto out;
3465    }
3466    loader_log(inst, VULKAN_LOADER_DRIVER_BIT, 0, "Found ICD manifest file %s, version %s", file_str, file_vers_str);
3467
3468    // Get the version of the driver manifest
3469    loader_api_version json_file_version = loader_make_full_version(loader_parse_version_string(file_vers_str));
3470
3471    // Loader only knows versions 1.0.0 and 1.0.1, anything above it is unknown
3472    if (loader_check_version_meets_required(loader_combine_version(1, 0, 2), json_file_version)) {
3473        loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
3474                   "loader_parse_icd_manifest: %s has unknown icd manifest file version %d.%d.%d. May cause errors.", file_str,
3475                   json_file_version.major, json_file_version.minor, json_file_version.patch);
3476    }
3477
3478    cJSON *itemICD = loader_cJSON_GetObjectItem(json, "ICD");
3479    if (itemICD == NULL) {
3480        loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
3481                   "loader_parse_icd_manifest: Can not find \'ICD\' object in ICD JSON file %s. Skipping ICD JSON", file_str);
3482        res = VK_ERROR_INCOMPATIBLE_DRIVER;
3483        goto out;
3484    }
3485
3486    item = loader_cJSON_GetObjectItem(itemICD, "library_path");
3487    if (item == NULL) {
3488        loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
3489                   "loader_parse_icd_manifest: Failed to find \'library_path\' object in ICD JSON file %s. Skipping ICD JSON.",
3490                   file_str);
3491        res = VK_ERROR_INCOMPATIBLE_DRIVER;
3492        goto out;
3493    }
3494    char *library_path = loader_cJSON_Print(item);
3495    if (!library_path) {
3496        loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
3497                   "loader_parse_icd_manifest: Failed retrieving ICD JSON %s \'library_path\' field. Skipping ICD JSON.", file_str);
3498        res = VK_ERROR_OUT_OF_HOST_MEMORY;
3499        goto out;
3500    }
3501
3502    if (strlen(library_path) == 0) {
3503        loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
3504                   "loader_parse_icd_manifest: ICD JSON %s \'library_path\' field is empty. Skipping ICD JSON.", file_str);
3505        res = VK_ERROR_INCOMPATIBLE_DRIVER;
3506        goto out;
3507    }
3508
3509    // Print out the paths being searched if debugging is enabled
3510    loader_log(inst, VULKAN_LOADER_DEBUG_BIT | VULKAN_LOADER_DRIVER_BIT, 0, "Searching for ICD drivers named %s", library_path);
3511    // This function takes ownership of library_path - so we don't need to clean it up
3512    res = combine_manifest_directory_and_library_path(inst, library_path, file_str, &icd->full_library_path);
3513    if (VK_SUCCESS != res) {
3514        goto out;
3515    }
3516
3517    item = loader_cJSON_GetObjectItem(itemICD, "api_version");
3518    if (item == NULL) {
3519        loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
3520                   "loader_parse_icd_manifest: ICD JSON %s does not have an \'api_version\' field. Skipping ICD JSON.", file_str);
3521        res = VK_ERROR_INCOMPATIBLE_DRIVER;
3522        goto out;
3523    }
3524    version_str = loader_cJSON_Print(item);
3525    if (NULL == version_str) {
3526        // Only reason the print can fail is if there was an allocation issue
3527        loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
3528                   "loader_parse_icd_manifest: Failed retrieving ICD JSON %s \'api_version\' field. Skipping ICD JSON.", file_str);
3529
3530        res = VK_ERROR_OUT_OF_HOST_MEMORY;
3531        goto out;
3532    }
3533    icd->version = loader_parse_version_string(version_str);
3534
3535    if (VK_API_VERSION_VARIANT(icd->version) != 0) {
3536        loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
3537                   "loader_parse_icd_manifest: Driver's ICD JSON %s \'api_version\' field contains a non-zero variant value of %d. "
3538                   " Skipping ICD JSON.",
3539                   file_str, VK_API_VERSION_VARIANT(icd->version));
3540        res = VK_ERROR_INCOMPATIBLE_DRIVER;
3541        goto out;
3542    }
3543
3544    // Skip over ICD's which contain a true "is_portability_driver" value whenever the application doesn't enable
3545    // portability enumeration.
3546    item = loader_cJSON_GetObjectItem(itemICD, "is_portability_driver");
3547    if (item != NULL && item->type == cJSON_True && inst && !inst->portability_enumeration_enabled) {
3548        if (skipped_portability_drivers) {
3549            *skipped_portability_drivers = true;
3550        }
3551        res = VK_ERROR_INCOMPATIBLE_DRIVER;
3552        goto out;
3553    }
3554
3555    item = loader_cJSON_GetObjectItem(itemICD, "library_arch");
3556    if (item != NULL) {
3557        library_arch_str = loader_cJSON_Print(item);
3558        if (NULL != library_arch_str) {
3559            // cJSON includes the quotes by default, so we need to look for those here
3560            if ((strncmp(library_arch_str, "32", 4) == 0 && sizeof(void *) != 4) ||
3561                (strncmp(library_arch_str, "64", 4) == 0 && sizeof(void *) != 8)) {
3562                loader_log(inst, VULKAN_LOADER_INFO_BIT, 0,
3563                           "loader_parse_icd_manifest: Driver library architecture doesn't match the current running "
3564                           "architecture, skipping this driver");
3565                res = VK_ERROR_INCOMPATIBLE_DRIVER;
3566                goto out;
3567            }
3568        } else {
3569            res = VK_ERROR_OUT_OF_HOST_MEMORY;
3570            goto out;
3571        }
3572    }
3573out:
3574    loader_cJSON_Delete(json);
3575    loader_instance_heap_free(inst, file_vers_str);
3576    loader_instance_heap_free(inst, version_str);
3577    loader_instance_heap_free(inst, library_arch_str);
3578    return res;
3579}
3580
3581// Try to find the Vulkan ICD driver(s).
3582//
3583// This function scans the default system loader path(s) or path specified by either the
3584// VK_DRIVER_FILES or VK_ICD_FILENAMES environment variable in order to find loadable
3585// VK ICDs manifest files.
3586// From these manifest files it finds the ICD libraries.
3587//
3588// skipped_portability_drivers is used to report whether the loader found drivers which report
3589// portability but the application didn't enable the bit to enumerate them
3590// Can be NULL
3591//
3592// \returns
3593// Vulkan result
3594// (on result == VK_SUCCESS) a list of icds that were discovered
3595VkResult loader_icd_scan(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list,
3596                         const VkInstanceCreateInfo *pCreateInfo, bool *skipped_portability_drivers) {
3597    VkResult res = VK_SUCCESS;
3598    struct loader_string_list manifest_files = {0};
3599    struct loader_envvar_filter select_filter = {0};
3600    struct loader_envvar_filter disable_filter = {0};
3601    struct ICDManifestInfo *icd_details = NULL;
3602
3603    // Set up the ICD Trampoline list so elements can be written into it.
3604    res = loader_scanned_icd_init(inst, icd_tramp_list);
3605    if (res == VK_ERROR_OUT_OF_HOST_MEMORY) {
3606        return res;
3607    }
3608
3609    bool direct_driver_loading_exclusive_mode = false;
3610    res = loader_scan_for_direct_drivers(inst, pCreateInfo, icd_tramp_list, &direct_driver_loading_exclusive_mode);
3611    if (res == VK_ERROR_OUT_OF_HOST_MEMORY) {
3612        goto out;
3613    }
3614    if (direct_driver_loading_exclusive_mode) {
3615        // Make sure to jump over the system & env-var driver discovery mechanisms if exclusive mode is set, even if no drivers
3616        // were successfully found through the direct driver loading mechanism
3617        goto out;
3618    }
3619
3620    // Parse the filter environment variables to determine if we have any special behavior
3621    res = parse_generic_filter_environment_var(inst, VK_DRIVERS_SELECT_ENV_VAR, &select_filter);
3622    if (VK_SUCCESS != res) {
3623        goto out;
3624    }
3625    res = parse_generic_filter_environment_var(inst, VK_DRIVERS_DISABLE_ENV_VAR, &disable_filter);
3626    if (VK_SUCCESS != res) {
3627        goto out;
3628    }
3629
3630    // Get a list of manifest files for ICDs
3631    res = loader_get_data_files(inst, LOADER_DATA_FILE_MANIFEST_DRIVER, NULL, &manifest_files);
3632    if (VK_SUCCESS != res) {
3633        goto out;
3634    }
3635
3636    icd_details = loader_stack_alloc(sizeof(struct ICDManifestInfo) * manifest_files.count);
3637    if (NULL == icd_details) {
3638        res = VK_ERROR_OUT_OF_HOST_MEMORY;
3639        goto out;
3640    }
3641    memset(icd_details, 0, sizeof(struct ICDManifestInfo) * manifest_files.count);
3642
3643    for (uint32_t i = 0; i < manifest_files.count; i++) {
3644        VkResult icd_res = VK_SUCCESS;
3645
3646        icd_res = loader_parse_icd_manifest(inst, manifest_files.list[i], &icd_details[i], skipped_portability_drivers);
3647        if (VK_ERROR_OUT_OF_HOST_MEMORY == icd_res) {
3648            res = icd_res;
3649            goto out;
3650        } else if (VK_ERROR_INCOMPATIBLE_DRIVER == icd_res) {
3651            continue;
3652        }
3653
3654        if (select_filter.count > 0 || disable_filter.count > 0) {
3655            // Get only the filename for comparing to the filters
3656            char *just_filename_str = strrchr(manifest_files.list[i], DIRECTORY_SYMBOL);
3657
3658            // No directory symbol, just the filename
3659            if (NULL == just_filename_str) {
3660                just_filename_str = manifest_files.list[i];
3661            } else {
3662                just_filename_str++;
3663            }
3664
3665            bool name_matches_select =
3666                (select_filter.count > 0 && check_name_matches_filter_environment_var(just_filename_str, &select_filter));
3667            bool name_matches_disable =
3668                (disable_filter.count > 0 && check_name_matches_filter_environment_var(just_filename_str, &disable_filter));
3669
3670            if (name_matches_disable && !name_matches_select) {
3671                loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
3672                           "Driver \"%s\" ignored because it was disabled by env var \'%s\'", just_filename_str,
3673                           VK_DRIVERS_DISABLE_ENV_VAR);
3674                continue;
3675            }
3676            if (select_filter.count != 0 && !name_matches_select) {
3677                loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
3678                           "Driver \"%s\" ignored because not selected by env var \'%s\'", just_filename_str,
3679                           VK_DRIVERS_SELECT_ENV_VAR);
3680                continue;
3681            }
3682        }
3683
3684        enum loader_layer_library_status lib_status;
3685        icd_res =
3686            loader_scanned_icd_add(inst, icd_tramp_list, icd_details[i].full_library_path, icd_details[i].version, &lib_status);
3687        if (VK_ERROR_OUT_OF_HOST_MEMORY == icd_res) {
3688            res = icd_res;
3689            goto out;
3690        } else if (VK_ERROR_INCOMPATIBLE_DRIVER == icd_res) {
3691            switch (lib_status) {
3692                case LOADER_LAYER_LIB_NOT_LOADED:
3693                case LOADER_LAYER_LIB_ERROR_FAILED_TO_LOAD:
3694                    loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
3695                               "loader_icd_scan: Failed loading library associated with ICD JSON %s. Ignoring this JSON",
3696                               icd_details[i].full_library_path);
3697                    break;
3698                case LOADER_LAYER_LIB_ERROR_WRONG_BIT_TYPE: {
3699                    loader_log(inst, VULKAN_LOADER_DRIVER_BIT, 0, "Requested ICD %s was wrong bit-type. Ignoring this JSON",
3700                               icd_details[i].full_library_path);
3701                    break;
3702                }
3703                case LOADER_LAYER_LIB_SUCCESS_LOADED:
3704                case LOADER_LAYER_LIB_ERROR_OUT_OF_MEMORY:
3705                    // Shouldn't be able to reach this but if it is, best to report a debug
3706                    loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
3707                               "Shouldn't reach this. A valid version of requested ICD %s was loaded but something bad "
3708                               "happened afterwards.",
3709                               icd_details[i].full_library_path);
3710                    break;
3711            }
3712        }
3713    }
3714
3715out:
3716    if (NULL != icd_details) {
3717        // Successfully got the icd_details structure, which means we need to free the paths contained within
3718        for (uint32_t i = 0; i < manifest_files.count; i++) {
3719            loader_instance_heap_free(inst, icd_details[i].full_library_path);
3720        }
3721    }
3722    free_string_list(inst, &manifest_files);
3723    return res;
3724}
3725
3726// Gets the layer data files corresponding to manifest_type & path_override, then parses the resulting json objects
3727// into instance_layers
3728// Manifest type must be either implicit or explicit
3729VkResult loader_parse_instance_layers(struct loader_instance *inst, enum loader_data_files_type manifest_type,
3730                                      const char *path_override, struct loader_layer_list *instance_layers) {
3731    assert(manifest_type == LOADER_DATA_FILE_MANIFEST_IMPLICIT_LAYER || manifest_type == LOADER_DATA_FILE_MANIFEST_EXPLICIT_LAYER);
3732    VkResult res = VK_SUCCESS;
3733    struct loader_string_list manifest_files = {0};
3734
3735    res = loader_get_data_files(inst, manifest_type, path_override, &manifest_files);
3736    if (VK_SUCCESS != res) {
3737        goto out;
3738    }
3739
3740    for (uint32_t i = 0; i < manifest_files.count; i++) {
3741        char *file_str = manifest_files.list[i];
3742        if (file_str == NULL) {
3743            continue;
3744        }
3745
3746        // Parse file into JSON struct
3747        cJSON *json = NULL;
3748        VkResult local_res = loader_get_json(inst, file_str, &json);
3749        if (VK_ERROR_OUT_OF_HOST_MEMORY == local_res) {
3750            res = VK_ERROR_OUT_OF_HOST_MEMORY;
3751            goto out;
3752        } else if (VK_SUCCESS != local_res || NULL == json) {
3753            continue;
3754        }
3755
3756        local_res = loader_add_layer_properties(inst, instance_layers, json,
3757                                                manifest_type == LOADER_DATA_FILE_MANIFEST_IMPLICIT_LAYER, file_str);
3758        loader_cJSON_Delete(json);
3759
3760        // If the error is anything other than out of memory we still want to try to load the other layers
3761        if (VK_ERROR_OUT_OF_HOST_MEMORY == local_res) {
3762            res = VK_ERROR_OUT_OF_HOST_MEMORY;
3763            goto out;
3764        }
3765    }
3766out:
3767    free_string_list(inst, &manifest_files);
3768
3769    return res;
3770}
3771
3772// Given a loader_layer_properties struct that is a valid override layer, concatenate the properties override paths and put them
3773// into the output parameter override_paths
3774VkResult get_override_layer_override_paths(struct loader_instance *inst, struct loader_layer_properties *prop,
3775                                           char **override_paths) {
3776    if (prop->override_paths.count > 0) {
3777        char *cur_write_ptr = NULL;
3778        size_t override_path_size = 0;
3779        for (uint32_t j = 0; j < prop->override_paths.count; j++) {
3780            override_path_size += determine_data_file_path_size(prop->override_paths.list[j], 0);
3781        }
3782        *override_paths = loader_instance_heap_alloc(inst, override_path_size, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
3783        if (*override_paths == NULL) {
3784            return VK_ERROR_OUT_OF_HOST_MEMORY;
3785        }
3786        cur_write_ptr = &(*override_paths)[0];
3787        for (uint32_t j = 0; j < prop->override_paths.count; j++) {
3788            copy_data_file_info(prop->override_paths.list[j], NULL, 0, &cur_write_ptr);
3789        }
3790        // Remove the last path separator
3791        --cur_write_ptr;
3792        assert(cur_write_ptr - (*override_paths) < (ptrdiff_t)override_path_size);
3793        *cur_write_ptr = '\0';
3794        loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0, "Override layer has override paths set to %s",
3795                   *override_paths);
3796    }
3797    return VK_SUCCESS;
3798}
3799
3800VkResult loader_scan_for_layers(struct loader_instance *inst, struct loader_layer_list *instance_layers,
3801                                const struct loader_envvar_all_filters *filters) {
3802    VkResult res = VK_SUCCESS;
3803    struct loader_layer_list settings_layers = {0};
3804    struct loader_layer_list regular_instance_layers = {0};
3805    bool override_layer_valid = false;
3806    char *override_paths = NULL;
3807
3808    bool should_search_for_other_layers = true;
3809    res = get_settings_layers(inst, &settings_layers, &should_search_for_other_layers);
3810    if (VK_SUCCESS != res) {
3811        goto out;
3812    }
3813
3814    // If we should not look for layers using other mechanisms, assign settings_layers to instance_layers and jump to the
3815    // output
3816    if (!should_search_for_other_layers) {
3817        *instance_layers = settings_layers;
3818        memset(&settings_layers, 0, sizeof(struct loader_layer_list));
3819        goto out;
3820    }
3821
3822    res = loader_parse_instance_layers(inst, LOADER_DATA_FILE_MANIFEST_IMPLICIT_LAYER, NULL, &regular_instance_layers);
3823    if (VK_SUCCESS != res) {
3824        goto out;
3825    }
3826
3827    // Remove any extraneous override layers.
3828    remove_all_non_valid_override_layers(inst, &regular_instance_layers);
3829
3830    // Check to see if the override layer is present, and use it's override paths.
3831    for (uint32_t i = 0; i < regular_instance_layers.count; i++) {
3832        struct loader_layer_properties *prop = &regular_instance_layers.list[i];
3833        if (prop->is_override && loader_implicit_layer_is_enabled(inst, filters, prop) && prop->override_paths.count > 0) {
3834            res = get_override_layer_override_paths(inst, prop, &override_paths);
3835            if (VK_SUCCESS != res) {
3836                goto out;
3837            }
3838            break;
3839        }
3840    }
3841
3842    // Get a list of manifest files for explicit layers
3843    res = loader_parse_instance_layers(inst, LOADER_DATA_FILE_MANIFEST_EXPLICIT_LAYER, override_paths, &regular_instance_layers);
3844    if (VK_SUCCESS != res) {
3845        goto out;
3846    }
3847
3848    // Verify any meta-layers in the list are valid and all the component layers are
3849    // actually present in the available layer list
3850    res = verify_all_meta_layers(inst, filters, &regular_instance_layers, &override_layer_valid);
3851    if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
3852        return res;
3853    }
3854
3855    if (override_layer_valid) {
3856        loader_remove_layers_in_blacklist(inst, &regular_instance_layers);
3857        if (NULL != inst) {
3858            inst->override_layer_present = true;
3859        }
3860    }
3861
3862    // Remove disabled layers
3863    for (uint32_t i = 0; i < regular_instance_layers.count; ++i) {
3864        if (!loader_layer_is_available(inst, filters, &regular_instance_layers.list[i])) {
3865            loader_remove_layer_in_list(inst, &regular_instance_layers, i);
3866            i--;
3867        }
3868    }
3869
3870    res = combine_settings_layers_with_regular_layers(inst, &settings_layers, &regular_instance_layers, instance_layers);
3871
3872out:
3873    loader_delete_layer_list_and_properties(inst, &settings_layers);
3874    loader_delete_layer_list_and_properties(inst, &regular_instance_layers);
3875
3876    loader_instance_heap_free(inst, override_paths);
3877    return res;
3878}
3879
3880VkResult loader_scan_for_implicit_layers(struct loader_instance *inst, struct loader_layer_list *instance_layers,
3881                                         const struct loader_envvar_all_filters *layer_filters) {
3882    VkResult res = VK_SUCCESS;
3883    struct loader_layer_list settings_layers = {0};
3884    struct loader_layer_list regular_instance_layers = {0};
3885    bool override_layer_valid = false;
3886    char *override_paths = NULL;
3887    bool implicit_metalayer_present = false;
3888
3889    bool should_search_for_other_layers = true;
3890    res = get_settings_layers(inst, &settings_layers, &should_search_for_other_layers);
3891    if (VK_SUCCESS != res) {
3892        goto out;
3893    }
3894
3895    // If we should not look for layers using other mechanisms, assign settings_layers to instance_layers and jump to the
3896    // output
3897    if (!should_search_for_other_layers) {
3898        *instance_layers = settings_layers;
3899        memset(&settings_layers, 0, sizeof(struct loader_layer_list));
3900        goto out;
3901    }
3902
3903    res = loader_parse_instance_layers(inst, LOADER_DATA_FILE_MANIFEST_IMPLICIT_LAYER, NULL, &regular_instance_layers);
3904    if (VK_SUCCESS != res) {
3905        goto out;
3906    }
3907
3908    // Remove any extraneous override layers.
3909    remove_all_non_valid_override_layers(inst, &regular_instance_layers);
3910
3911    // Check to see if either the override layer is present, or another implicit meta-layer.
3912    // Each of these may require explicit layers to be enabled at this time.
3913    for (uint32_t i = 0; i < regular_instance_layers.count; i++) {
3914        struct loader_layer_properties *prop = &regular_instance_layers.list[i];
3915        if (prop->is_override && loader_implicit_layer_is_enabled(inst, layer_filters, prop)) {
3916            override_layer_valid = true;
3917            res = get_override_layer_override_paths(inst, prop, &override_paths);
3918            if (VK_SUCCESS != res) {
3919                goto out;
3920            }
3921        } else if (!prop->is_override && prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER) {
3922            implicit_metalayer_present = true;
3923        }
3924    }
3925
3926    // If either the override layer or an implicit meta-layer are present, we need to add
3927    // explicit layer info as well.  Not to worry, though, all explicit layers not included
3928    // in the override layer will be removed below in loader_remove_layers_in_blacklist().
3929    if (override_layer_valid || implicit_metalayer_present) {
3930        res =
3931            loader_parse_instance_layers(inst, LOADER_DATA_FILE_MANIFEST_EXPLICIT_LAYER, override_paths, &regular_instance_layers);
3932        if (VK_SUCCESS != res) {
3933            goto out;
3934        }
3935    }
3936
3937    // Verify any meta-layers in the list are valid and all the component layers are
3938    // actually present in the available layer list
3939    res = verify_all_meta_layers(inst, layer_filters, &regular_instance_layers, &override_layer_valid);
3940    if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
3941        return res;
3942    }
3943
3944    if (override_layer_valid || implicit_metalayer_present) {
3945        loader_remove_layers_not_in_implicit_meta_layers(inst, &regular_instance_layers);
3946        if (override_layer_valid && inst != NULL) {
3947            inst->override_layer_present = true;
3948        }
3949    }
3950
3951    // Remove disabled layers
3952    for (uint32_t i = 0; i < regular_instance_layers.count; ++i) {
3953        if (!loader_implicit_layer_is_enabled(inst, layer_filters, &regular_instance_layers.list[i])) {
3954            loader_remove_layer_in_list(inst, &regular_instance_layers, i);
3955            i--;
3956        }
3957    }
3958
3959    res = combine_settings_layers_with_regular_layers(inst, &settings_layers, &regular_instance_layers, instance_layers);
3960
3961out:
3962    loader_delete_layer_list_and_properties(inst, &settings_layers);
3963    loader_delete_layer_list_and_properties(inst, &regular_instance_layers);
3964
3965    loader_instance_heap_free(inst, override_paths);
3966    return res;
3967}
3968
3969VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL loader_gpdpa_instance_terminator(VkInstance inst, const char *pName) {
3970    // inst is not wrapped
3971    if (inst == VK_NULL_HANDLE) {
3972        return NULL;
3973    }
3974
3975    VkLayerInstanceDispatchTable *disp_table = *(VkLayerInstanceDispatchTable **)inst;
3976
3977    if (disp_table == NULL) return NULL;
3978
3979    struct loader_instance *loader_inst = loader_get_instance(inst);
3980
3981    if (loader_inst->instance_finished_creation) {
3982        disp_table = &loader_inst->terminator_dispatch;
3983    }
3984
3985    bool found_name;
3986    void *addr = loader_lookup_instance_dispatch_table(disp_table, pName, &found_name);
3987    if (found_name) {
3988        return addr;
3989    }
3990
3991    // Check if any drivers support the function, and if so, add it to the unknown function list
3992    addr = loader_phys_dev_ext_gpa_term(loader_get_instance(inst), pName);
3993    if (NULL != addr) return addr;
3994
3995    // Don't call down the chain, this would be an infinite loop
3996    loader_log(NULL, VULKAN_LOADER_DEBUG_BIT, 0, "loader_gpdpa_instance_terminator() unrecognized name %s", pName);
3997    return NULL;
3998}
3999
4000VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL loader_gpa_instance_terminator(VkInstance inst, const char *pName) {
4001    // Global functions - Do not need a valid instance handle to query
4002    if (!strcmp(pName, "vkGetInstanceProcAddr")) {
4003        return (PFN_vkVoidFunction)loader_gpa_instance_terminator;
4004    }
4005    if (!strcmp(pName, "vk_layerGetPhysicalDeviceProcAddr")) {
4006        return (PFN_vkVoidFunction)loader_gpdpa_instance_terminator;
4007    }
4008    if (!strcmp(pName, "vkCreateInstance")) {
4009        return (PFN_vkVoidFunction)terminator_CreateInstance;
4010    }
4011
4012    // While the spec is very clear that querying vkCreateDevice requires a valid VkInstance, because the loader allowed querying
4013    // with a NULL VkInstance handle for a long enough time, it is impractical to fix this bug in the loader
4014
4015    // As such, this is a bug to maintain compatibility for the RTSS layer (Riva Tuner Statistics Server) but may
4016    // be depended upon by other layers out in the wild.
4017    if (!strcmp(pName, "vkCreateDevice")) {
4018        return (PFN_vkVoidFunction)terminator_CreateDevice;
4019    }
4020
4021    // inst is not wrapped
4022    if (inst == VK_NULL_HANDLE) {
4023        return NULL;
4024    }
4025    VkLayerInstanceDispatchTable *disp_table = *(VkLayerInstanceDispatchTable **)inst;
4026
4027    if (disp_table == NULL) return NULL;
4028
4029    struct loader_instance *loader_inst = loader_get_instance(inst);
4030
4031    // The VK_EXT_debug_utils functions need a special case here so the terminators can still be found from
4032    // vkGetInstanceProcAddr This is because VK_EXT_debug_utils is an instance level extension with device level functions, and
4033    // is 'supported' by the loader.
4034    // These functions need a terminator to handle the case of a driver not supporting VK_EXT_debug_utils when there are layers
4035    // present which not check for NULL before calling the function.
4036    if (!strcmp(pName, "vkSetDebugUtilsObjectNameEXT")) {
4037        return loader_inst->enabled_known_extensions.ext_debug_utils ? (PFN_vkVoidFunction)terminator_SetDebugUtilsObjectNameEXT
4038                                                                     : NULL;
4039    }
4040    if (!strcmp(pName, "vkSetDebugUtilsObjectTagEXT")) {
4041        return loader_inst->enabled_known_extensions.ext_debug_utils ? (PFN_vkVoidFunction)terminator_SetDebugUtilsObjectTagEXT
4042                                                                     : NULL;
4043    }
4044    if (!strcmp(pName, "vkQueueBeginDebugUtilsLabelEXT")) {
4045        return loader_inst->enabled_known_extensions.ext_debug_utils ? (PFN_vkVoidFunction)terminator_QueueBeginDebugUtilsLabelEXT
4046                                                                     : NULL;
4047    }
4048    if (!strcmp(pName, "vkQueueEndDebugUtilsLabelEXT")) {
4049        return loader_inst->enabled_known_extensions.ext_debug_utils ? (PFN_vkVoidFunction)terminator_QueueEndDebugUtilsLabelEXT
4050                                                                     : NULL;
4051    }
4052    if (!strcmp(pName, "vkQueueInsertDebugUtilsLabelEXT")) {
4053        return loader_inst->enabled_known_extensions.ext_debug_utils ? (PFN_vkVoidFunction)terminator_QueueInsertDebugUtilsLabelEXT
4054                                                                     : NULL;
4055    }
4056    if (!strcmp(pName, "vkCmdBeginDebugUtilsLabelEXT")) {
4057        return loader_inst->enabled_known_extensions.ext_debug_utils ? (PFN_vkVoidFunction)terminator_CmdBeginDebugUtilsLabelEXT
4058                                                                     : NULL;
4059    }
4060    if (!strcmp(pName, "vkCmdEndDebugUtilsLabelEXT")) {
4061        return loader_inst->enabled_known_extensions.ext_debug_utils ? (PFN_vkVoidFunction)terminator_CmdEndDebugUtilsLabelEXT
4062                                                                     : NULL;
4063    }
4064    if (!strcmp(pName, "vkCmdInsertDebugUtilsLabelEXT")) {
4065        return loader_inst->enabled_known_extensions.ext_debug_utils ? (PFN_vkVoidFunction)terminator_CmdInsertDebugUtilsLabelEXT
4066                                                                     : NULL;
4067    }
4068
4069    if (loader_inst->instance_finished_creation) {
4070        disp_table = &loader_inst->terminator_dispatch;
4071    }
4072
4073    bool found_name;
4074    void *addr = loader_lookup_instance_dispatch_table(disp_table, pName, &found_name);
4075    if (found_name) {
4076        return addr;
4077    }
4078
4079    // Check if it is an unknown physical device function, to see if any drivers support it.
4080    addr = loader_phys_dev_ext_gpa_term(loader_get_instance(inst), pName);
4081    if (addr) {
4082        return addr;
4083    }
4084
4085    // Assume it is an unknown device function, check to see if any drivers support it.
4086    addr = loader_dev_ext_gpa_term(loader_get_instance(inst), pName);
4087    if (addr) {
4088        return addr;
4089    }
4090
4091    // Don't call down the chain, this would be an infinite loop
4092    loader_log(NULL, VULKAN_LOADER_DEBUG_BIT, 0, "loader_gpa_instance_terminator() unrecognized name %s", pName);
4093    return NULL;
4094}
4095
4096VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL loader_gpa_device_terminator(VkDevice device, const char *pName) {
4097    struct loader_device *dev;
4098    struct loader_icd_term *icd_term = loader_get_icd_and_device(device, &dev, NULL);
4099
4100    // Return this function if a layer above here is asking for the vkGetDeviceProcAddr.
4101    // This is so we can properly intercept any device commands needing a terminator.
4102    if (!strcmp(pName, "vkGetDeviceProcAddr")) {
4103        return (PFN_vkVoidFunction)loader_gpa_device_terminator;
4104    }
4105
4106    // NOTE: Device Funcs needing Trampoline/Terminator.
4107    // Overrides for device functions needing a trampoline and
4108    // a terminator because certain device entry-points still need to go
4109    // through a terminator before hitting the ICD.  This could be for
4110    // several reasons, but the main one is currently unwrapping an
4111    // object before passing the appropriate info along to the ICD.
4112    // This is why we also have to override the direct ICD call to
4113    // vkGetDeviceProcAddr to intercept those calls.
4114    // If the pName is for a 'known' function but isn't available, due to
4115    // the corresponding extension/feature not being enabled, we need to
4116    // return NULL and not call down to the driver's GetDeviceProcAddr.
4117    if (NULL != dev) {
4118        bool found_name = false;
4119        PFN_vkVoidFunction addr = get_extension_device_proc_terminator(dev, pName, &found_name);
4120        if (found_name) {
4121            return addr;
4122        }
4123    }
4124
4125    if (icd_term == NULL) {
4126        return NULL;
4127    }
4128
4129    return icd_term->dispatch.GetDeviceProcAddr(device, pName);
4130}
4131
4132struct loader_instance *loader_get_instance(const VkInstance instance) {
4133    // look up the loader_instance in our list by comparing dispatch tables, as
4134    // there is no guarantee the instance is still a loader_instance* after any
4135    // layers which wrap the instance object.
4136    const VkLayerInstanceDispatchTable *disp;
4137    struct loader_instance *ptr_instance = (struct loader_instance *)instance;
4138    if (VK_NULL_HANDLE == instance || LOADER_MAGIC_NUMBER != ptr_instance->magic) {
4139        return NULL;
4140    } else {
4141        disp = loader_get_instance_layer_dispatch(instance);
4142        loader_platform_thread_lock_mutex(&loader_global_instance_list_lock);
4143        for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
4144            if (&inst->disp->layer_inst_disp == disp) {
4145                ptr_instance = inst;
4146                break;
4147            }
4148        }
4149        loader_platform_thread_unlock_mutex(&loader_global_instance_list_lock);
4150    }
4151    return ptr_instance;
4152}
4153
4154loader_platform_dl_handle loader_open_layer_file(const struct loader_instance *inst, struct loader_layer_properties *prop) {
4155    char* libPath = prop->lib_name;
4156#if defined(__OHOS__)
4157    char *debug_layer_name = loader_secure_getenv("debug.graphic.debug_layer", inst);
4158    char *debug_hap_name = loader_secure_getenv("debug.graphic.debug_hap", inst);
4159    bool isDebugLayer = false;
4160    char* debugLayerLibPath = NULL;
4161    if (NULL != debug_layer_name && '\0' != debug_layer_name[0] && InitBundleInfo(debug_hap_name)) {
4162        const char lib_prefix[] = "lib";
4163        const char so_suffix[] = ".so";
4164        size_t totalLen = strlen(debug_layer_name) + strlen(lib_prefix) + strlen(so_suffix) + 1;
4165        char* layerSoName = loader_instance_heap_calloc(inst, totalLen, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
4166        if (layerSoName == NULL) {
4167            loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_LAYER_BIT, 0, "malloc layerSoName fail");
4168            goto mallocErr;
4169        }
4170        strncpy(layerSoName, lib_prefix, totalLen);
4171        strncat(layerSoName, debug_layer_name, totalLen);
4172        strncat(layerSoName, so_suffix, totalLen);
4173        if (strcmp(layerSoName, libPath) == 0) {
4174            isDebugLayer = true;
4175            debugLayerLibPath = GetDebugLayerLibPath(inst, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
4176            if(debugLayerLibPath == NULL) {
4177                loader_instance_heap_free(inst, layerSoName);
4178                isDebugLayer = false;
4179                goto mallocErr;
4180            }
4181            size_t totalLength = strlen(libPath) + strlen(debugLayerLibPath) + 1;
4182            libPath = loader_instance_heap_calloc(inst, totalLength, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
4183            if (libPath == NULL) {
4184                loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_LAYER_BIT, 0, "malloc libPath fail");
4185                loader_instance_heap_free(inst, layerSoName);
4186                loader_instance_heap_free(inst, debugLayerLibPath);
4187                libPath = prop->lib_name;
4188                isDebugLayer = false;
4189                goto mallocErr;
4190            }
4191            strncpy(libPath, debugLayerLibPath, totalLength);
4192            strncat(libPath, prop->lib_name, totalLength);
4193        } else {
4194            loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_LAYER_BIT, 0, "layerSoName != libPath : %s != %s",
4195                layerSoName, libPath);
4196        }
4197        loader_instance_heap_free(inst, layerSoName);
4198    }
4199mallocErr:
4200    loader_free_getenv(debug_layer_name, inst);
4201    loader_free_getenv(debug_hap_name, inst);
4202#endif
4203    loader_log(inst, VULKAN_LOADER_DEBUG_BIT | VULKAN_LOADER_LAYER_BIT, 0, "try to open libPath: %s", libPath);
4204    if ((prop->lib_handle = loader_platform_open_library(libPath)) == NULL) {
4205        loader_handle_load_library_error(inst, prop->lib_name, &prop->lib_status);
4206    } else {
4207        prop->lib_status = LOADER_LAYER_LIB_SUCCESS_LOADED;
4208        loader_log(inst, VULKAN_LOADER_DEBUG_BIT | VULKAN_LOADER_LAYER_BIT, 0, "Loading layer library %s", prop->lib_name);
4209    }
4210#if defined(__OHOS__)
4211    if (isDebugLayer) {
4212        loader_instance_heap_free(inst, debugLayerLibPath);
4213        loader_instance_heap_free(inst, libPath);
4214    }
4215#endif
4216    return prop->lib_handle;
4217}
4218
4219// Go through the search_list and find any layers which match type. If layer
4220// type match is found in then add it to ext_list.
4221VkResult loader_add_implicit_layers(const struct loader_instance *inst, const struct loader_envvar_all_filters *filters,
4222                                    struct loader_pointer_layer_list *target_list,
4223                                    struct loader_pointer_layer_list *expanded_target_list,
4224                                    const struct loader_layer_list *source_list) {
4225    for (uint32_t src_layer = 0; src_layer < source_list->count; src_layer++) {
4226        struct loader_layer_properties *prop = &source_list->list[src_layer];
4227        if (0 == (prop->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER)) {
4228            VkResult result = loader_add_implicit_layer(inst, prop, filters, target_list, expanded_target_list, source_list);
4229            if (result == VK_ERROR_OUT_OF_HOST_MEMORY) return result;
4230        }
4231    }
4232    return VK_SUCCESS;
4233}
4234
4235void warn_if_layers_are_older_than_application(struct loader_instance *inst) {
4236    for (uint32_t i = 0; i < inst->expanded_activated_layer_list.count; i++) {
4237        // Verify that the layer api version is at least that of the application's request, if not, throw a warning since
4238        // undefined behavior could occur.
4239        struct loader_layer_properties *prop = inst->expanded_activated_layer_list.list[i];
4240        loader_api_version prop_spec_version = loader_make_version(prop->info.specVersion);
4241        if (!loader_check_version_meets_required(inst->app_api_version, prop_spec_version)) {
4242            loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
4243                       "Layer %s uses API version %u.%u which is older than the application specified "
4244                       "API version of %u.%u. May cause issues.",
4245                       prop->info.layerName, prop_spec_version.major, prop_spec_version.minor, inst->app_api_version.major,
4246                       inst->app_api_version.minor);
4247        }
4248    }
4249}
4250
4251VkResult loader_enable_instance_layers(struct loader_instance *inst, const VkInstanceCreateInfo *pCreateInfo,
4252                                       const struct loader_layer_list *instance_layers,
4253                                       const struct loader_envvar_all_filters *layer_filters) {
4254    VkResult res = VK_SUCCESS;
4255
4256    assert(inst && "Cannot have null instance");
4257
4258    if (!loader_init_pointer_layer_list(inst, &inst->app_activated_layer_list)) {
4259        loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
4260                   "loader_enable_instance_layers: Failed to initialize application version of the layer list");
4261        res = VK_ERROR_OUT_OF_HOST_MEMORY;
4262        goto out;
4263    }
4264
4265    if (!loader_init_pointer_layer_list(inst, &inst->expanded_activated_layer_list)) {
4266        loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
4267                   "loader_enable_instance_layers: Failed to initialize expanded version of the layer list");
4268        res = VK_ERROR_OUT_OF_HOST_MEMORY;
4269        goto out;
4270    }
4271
4272    if (inst->settings.settings_active) {
4273        res = enable_correct_layers_from_settings(inst, layer_filters, pCreateInfo->enabledLayerCount,
4274                                                  pCreateInfo->ppEnabledLayerNames, &inst->instance_layer_list,
4275                                                  &inst->app_activated_layer_list, &inst->expanded_activated_layer_list);
4276        warn_if_layers_are_older_than_application(inst);
4277
4278        goto out;
4279    }
4280
4281    // Add any implicit layers first
4282    res = loader_add_implicit_layers(inst, layer_filters, &inst->app_activated_layer_list, &inst->expanded_activated_layer_list,
4283                                     instance_layers);
4284    if (res != VK_SUCCESS) {
4285        goto out;
4286    }
4287
4288    // Add any layers specified via environment variable next
4289    res = loader_add_environment_layers(inst, VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER, layer_filters, &inst->app_activated_layer_list,
4290                                        &inst->expanded_activated_layer_list, instance_layers);
4291    if (res != VK_SUCCESS) {
4292        goto out;
4293    }
4294
4295    // Add layers specified by the application
4296    res = loader_add_layer_names_to_list(inst, layer_filters, &inst->app_activated_layer_list, &inst->expanded_activated_layer_list,
4297                                         pCreateInfo->enabledLayerCount, pCreateInfo->ppEnabledLayerNames, instance_layers);
4298
4299    warn_if_layers_are_older_than_application(inst);
4300out:
4301    return res;
4302}
4303
4304// Determine the layer interface version to use.
4305bool loader_get_layer_interface_version(PFN_vkNegotiateLoaderLayerInterfaceVersion fp_negotiate_layer_version,
4306                                        VkNegotiateLayerInterface *interface_struct) {
4307    memset(interface_struct, 0, sizeof(VkNegotiateLayerInterface));
4308    interface_struct->sType = LAYER_NEGOTIATE_INTERFACE_STRUCT;
4309    interface_struct->loaderLayerInterfaceVersion = 1;
4310    interface_struct->pNext = NULL;
4311
4312    if (fp_negotiate_layer_version != NULL) {
4313        // Layer supports the negotiation API, so call it with the loader's
4314        // latest version supported
4315        interface_struct->loaderLayerInterfaceVersion = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
4316        VkResult result = fp_negotiate_layer_version(interface_struct);
4317
4318        if (result != VK_SUCCESS) {
4319            // Layer no longer supports the loader's latest interface version so
4320            // fail loading the Layer
4321            return false;
4322        }
4323    }
4324
4325    if (interface_struct->loaderLayerInterfaceVersion < MIN_SUPPORTED_LOADER_LAYER_INTERFACE_VERSION) {
4326        // Loader no longer supports the layer's latest interface version so
4327        // fail loading the layer
4328        return false;
4329    }
4330
4331    return true;
4332}
4333
4334// Every extension that has a loader-defined trampoline needs to be marked as enabled or disabled so that we know whether or
4335// not to return that trampoline when vkGetDeviceProcAddr is called
4336void setup_logical_device_enabled_layer_extensions(const struct loader_instance *inst, struct loader_device *dev,
4337                                                   const struct loader_extension_list *icd_exts,
4338                                                   const VkDeviceCreateInfo *pCreateInfo) {
4339    // Can only setup debug marker as debug utils is an instance extensions.
4340    for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; ++i) {
4341        if (!strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_EXT_DEBUG_MARKER_EXTENSION_NAME)) {
4342            // Check if its supported by the driver
4343            for (uint32_t j = 0; j < icd_exts->count; ++j) {
4344                if (!strcmp(icd_exts->list[j].extensionName, VK_EXT_DEBUG_MARKER_EXTENSION_NAME)) {
4345                    dev->layer_extensions.ext_debug_marker_enabled = true;
4346                }
4347            }
4348            // also check if any layers support it.
4349            for (uint32_t j = 0; j < inst->app_activated_layer_list.count; j++) {
4350                struct loader_layer_properties *layer = inst->app_activated_layer_list.list[j];
4351                for (uint32_t k = 0; k < layer->device_extension_list.count; k++) {
4352                    if (!strcmp(layer->device_extension_list.list[k].props.extensionName, VK_EXT_DEBUG_MARKER_EXTENSION_NAME)) {
4353                        dev->layer_extensions.ext_debug_marker_enabled = true;
4354                    }
4355                }
4356            }
4357        }
4358    }
4359}
4360
4361VKAPI_ATTR VkResult VKAPI_CALL loader_layer_create_device(VkInstance instance, VkPhysicalDevice physicalDevice,
4362                                                          const VkDeviceCreateInfo *pCreateInfo,
4363                                                          const VkAllocationCallbacks *pAllocator, VkDevice *pDevice,
4364                                                          PFN_vkGetInstanceProcAddr layerGIPA, PFN_vkGetDeviceProcAddr *nextGDPA) {
4365    VkResult res;
4366    VkPhysicalDevice internal_device = VK_NULL_HANDLE;
4367    struct loader_device *dev = NULL;
4368    struct loader_instance *inst = NULL;
4369
4370    if (instance != VK_NULL_HANDLE) {
4371        inst = loader_get_instance(instance);
4372        internal_device = physicalDevice;
4373    } else {
4374        struct loader_physical_device_tramp *phys_dev = (struct loader_physical_device_tramp *)physicalDevice;
4375        internal_device = phys_dev->phys_dev;
4376        inst = (struct loader_instance *)phys_dev->this_instance;
4377    }
4378
4379    // Get the physical device (ICD) extensions
4380    struct loader_extension_list icd_exts = {0};
4381    icd_exts.list = NULL;
4382    res = loader_init_generic_list(inst, (struct loader_generic_list *)&icd_exts, sizeof(VkExtensionProperties));
4383    if (VK_SUCCESS != res) {
4384        loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "vkCreateDevice: Failed to create ICD extension list");
4385        goto out;
4386    }
4387
4388    PFN_vkEnumerateDeviceExtensionProperties enumDeviceExtensionProperties = NULL;
4389    if (layerGIPA != NULL) {
4390        enumDeviceExtensionProperties =
4391            (PFN_vkEnumerateDeviceExtensionProperties)layerGIPA(instance, "vkEnumerateDeviceExtensionProperties");
4392    } else {
4393        enumDeviceExtensionProperties = inst->disp->layer_inst_disp.EnumerateDeviceExtensionProperties;
4394    }
4395    res = loader_add_device_extensions(inst, enumDeviceExtensionProperties, internal_device, "Unknown", &icd_exts);
4396    if (res != VK_SUCCESS) {
4397        loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "vkCreateDevice: Failed to add extensions to list");
4398        goto out;
4399    }
4400
4401    // Make sure requested extensions to be enabled are supported
4402    res = loader_validate_device_extensions(inst, &inst->expanded_activated_layer_list, &icd_exts, pCreateInfo);
4403    if (res != VK_SUCCESS) {
4404        loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "vkCreateDevice: Failed to validate extensions in list");
4405        goto out;
4406    }
4407
4408    dev = loader_create_logical_device(inst, pAllocator);
4409    if (dev == NULL) {
4410        res = VK_ERROR_OUT_OF_HOST_MEMORY;
4411        goto out;
4412    }
4413
4414    setup_logical_device_enabled_layer_extensions(inst, dev, &icd_exts, pCreateInfo);
4415
4416    res = loader_create_device_chain(internal_device, pCreateInfo, pAllocator, inst, dev, layerGIPA, nextGDPA);
4417    if (res != VK_SUCCESS) {
4418        loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "vkCreateDevice:  Failed to create device chain.");
4419        goto out;
4420    }
4421
4422    *pDevice = dev->chain_device;
4423
4424    // Initialize any device extension dispatch entry's from the instance list
4425    loader_init_dispatch_dev_ext(inst, dev);
4426
4427    // Initialize WSI device extensions as part of core dispatch since loader
4428    // has dedicated trampoline code for these
4429    loader_init_device_extension_dispatch_table(&dev->loader_dispatch, inst->disp->layer_inst_disp.GetInstanceProcAddr,
4430                                                dev->loader_dispatch.core_dispatch.GetDeviceProcAddr, inst->instance, *pDevice);
4431
4432out:
4433
4434    // Failure cleanup
4435    if (VK_SUCCESS != res) {
4436        if (NULL != dev) {
4437            // Find the icd_term this device belongs to then remove it from that icd_term.
4438            // Need to iterate the linked lists and remove the device from it. Don't delete
4439            // the device here since it may not have been added to the icd_term and there
4440            // are other allocations attached to it.
4441            struct loader_icd_term *icd_term = inst->icd_terms;
4442            bool found = false;
4443            while (!found && NULL != icd_term) {
4444                struct loader_device *cur_dev = icd_term->logical_device_list;
4445                struct loader_device *prev_dev = NULL;
4446                while (NULL != cur_dev) {
4447                    if (cur_dev == dev) {
4448                        if (cur_dev == icd_term->logical_device_list) {
4449                            icd_term->logical_device_list = cur_dev->next;
4450                        } else if (prev_dev) {
4451                            prev_dev->next = cur_dev->next;
4452                        }
4453
4454                        found = true;
4455                        break;
4456                    }
4457                    prev_dev = cur_dev;
4458                    cur_dev = cur_dev->next;
4459                }
4460                icd_term = icd_term->next;
4461            }
4462            // Now destroy the device and the allocations associated with it.
4463            loader_destroy_logical_device(dev, pAllocator);
4464        }
4465    }
4466
4467    if (NULL != icd_exts.list) {
4468        loader_destroy_generic_list(inst, (struct loader_generic_list *)&icd_exts);
4469    }
4470    return res;
4471}
4472
4473VKAPI_ATTR void VKAPI_CALL loader_layer_destroy_device(VkDevice device, const VkAllocationCallbacks *pAllocator,
4474                                                       PFN_vkDestroyDevice destroyFunction) {
4475    struct loader_device *dev;
4476
4477    if (device == VK_NULL_HANDLE) {
4478        return;
4479    }
4480
4481    struct loader_icd_term *icd_term = loader_get_icd_and_device(device, &dev, NULL);
4482
4483    destroyFunction(device, pAllocator);
4484    if (NULL != dev) {
4485        dev->chain_device = NULL;
4486        dev->icd_device = NULL;
4487        loader_remove_logical_device(icd_term, dev, pAllocator);
4488    }
4489}
4490
4491// Given the list of layers to activate in the loader_instance
4492// structure. This function will add a VkLayerInstanceCreateInfo
4493// structure to the VkInstanceCreateInfo.pNext pointer.
4494// Each activated layer will have it's own VkLayerInstanceLink
4495// structure that tells the layer what Get*ProcAddr to call to
4496// get function pointers to the next layer down.
4497// Once the chain info has been created this function will
4498// execute the CreateInstance call chain. Each layer will
4499// then have an opportunity in it's CreateInstance function
4500// to setup it's dispatch table when the lower layer returns
4501// successfully.
4502// Each layer can wrap or not-wrap the returned VkInstance object
4503// as it sees fit.
4504// The instance chain is terminated by a loader function
4505// that will call CreateInstance on all available ICD's and
4506// cache those VkInstance objects for future use.
4507VkResult loader_create_instance_chain(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
4508                                      struct loader_instance *inst, VkInstance *created_instance) {
4509    uint32_t num_activated_layers = 0;
4510    struct activated_layer_info *activated_layers = NULL;
4511    VkLayerInstanceCreateInfo chain_info;
4512    VkLayerInstanceLink *layer_instance_link_info = NULL;
4513    VkInstanceCreateInfo loader_create_info;
4514    VkResult res;
4515
4516    PFN_vkGetInstanceProcAddr next_gipa = loader_gpa_instance_terminator;
4517    PFN_vkGetInstanceProcAddr cur_gipa = loader_gpa_instance_terminator;
4518    PFN_vkGetDeviceProcAddr cur_gdpa = loader_gpa_device_terminator;
4519    PFN_GetPhysicalDeviceProcAddr next_gpdpa = loader_gpdpa_instance_terminator;
4520    PFN_GetPhysicalDeviceProcAddr cur_gpdpa = loader_gpdpa_instance_terminator;
4521
4522    memcpy(&loader_create_info, pCreateInfo, sizeof(VkInstanceCreateInfo));
4523
4524    if (inst->expanded_activated_layer_list.count > 0) {
4525        chain_info.u.pLayerInfo = NULL;
4526        chain_info.pNext = pCreateInfo->pNext;
4527        chain_info.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO;
4528        chain_info.function = VK_LAYER_LINK_INFO;
4529        loader_create_info.pNext = &chain_info;
4530
4531        layer_instance_link_info = loader_stack_alloc(sizeof(VkLayerInstanceLink) * inst->expanded_activated_layer_list.count);
4532        if (!layer_instance_link_info) {
4533            loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
4534                       "loader_create_instance_chain: Failed to alloc Instance objects for layer");
4535            return VK_ERROR_OUT_OF_HOST_MEMORY;
4536        }
4537
4538        activated_layers = loader_stack_alloc(sizeof(struct activated_layer_info) * inst->expanded_activated_layer_list.count);
4539        if (!activated_layers) {
4540            loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
4541                       "loader_create_instance_chain: Failed to alloc activated layer storage array");
4542            return VK_ERROR_OUT_OF_HOST_MEMORY;
4543        }
4544
4545        // Create instance chain of enabled layers
4546        for (int32_t i = inst->expanded_activated_layer_list.count - 1; i >= 0; i--) {
4547            struct loader_layer_properties *layer_prop = inst->expanded_activated_layer_list.list[i];
4548            loader_platform_dl_handle lib_handle;
4549
4550            // Skip it if a Layer with the same name has been already successfully activated
4551            if (loader_names_array_has_layer_property(&layer_prop->info, num_activated_layers, activated_layers)) {
4552                continue;
4553            }
4554
4555            lib_handle = loader_open_layer_file(inst, layer_prop);
4556            if (layer_prop->lib_status == LOADER_LAYER_LIB_ERROR_OUT_OF_MEMORY) {
4557                return VK_ERROR_OUT_OF_HOST_MEMORY;
4558            }
4559            if (!lib_handle) {
4560                continue;
4561            }
4562
4563            if (NULL == layer_prop->functions.negotiate_layer_interface) {
4564                PFN_vkNegotiateLoaderLayerInterfaceVersion negotiate_interface = NULL;
4565                bool functions_in_interface = false;
4566                if (!layer_prop->functions.str_negotiate_interface || strlen(layer_prop->functions.str_negotiate_interface) == 0) {
4567                    negotiate_interface = (PFN_vkNegotiateLoaderLayerInterfaceVersion)loader_platform_get_proc_address(
4568                        lib_handle, "vkNegotiateLoaderLayerInterfaceVersion");
4569                } else {
4570                    negotiate_interface = (PFN_vkNegotiateLoaderLayerInterfaceVersion)loader_platform_get_proc_address(
4571                        lib_handle, layer_prop->functions.str_negotiate_interface);
4572                }
4573
4574                // If we can negotiate an interface version, then we can also
4575                // get everything we need from the one function call, so try
4576                // that first, and see if we can get all the function pointers
4577                // necessary from that one call.
4578                if (NULL != negotiate_interface) {
4579                    layer_prop->functions.negotiate_layer_interface = negotiate_interface;
4580
4581                    VkNegotiateLayerInterface interface_struct;
4582
4583                    if (loader_get_layer_interface_version(negotiate_interface, &interface_struct)) {
4584                        // Go ahead and set the properties version to the
4585                        // correct value.
4586                        layer_prop->interface_version = interface_struct.loaderLayerInterfaceVersion;
4587
4588                        // If the interface is 2 or newer, we have access to the
4589                        // new GetPhysicalDeviceProcAddr function, so grab it,
4590                        // and the other necessary functions, from the
4591                        // structure.
4592                        if (interface_struct.loaderLayerInterfaceVersion > 1) {
4593                            cur_gipa = interface_struct.pfnGetInstanceProcAddr;
4594                            cur_gdpa = interface_struct.pfnGetDeviceProcAddr;
4595                            cur_gpdpa = interface_struct.pfnGetPhysicalDeviceProcAddr;
4596                            if (cur_gipa != NULL) {
4597                                // We've set the functions, so make sure we
4598                                // don't do the unnecessary calls later.
4599                                functions_in_interface = true;
4600                            }
4601                        }
4602                    }
4603                }
4604
4605                if (!functions_in_interface) {
4606                    if ((cur_gipa = layer_prop->functions.get_instance_proc_addr) == NULL) {
4607                        if (layer_prop->functions.str_gipa == NULL || strlen(layer_prop->functions.str_gipa) == 0) {
4608                            cur_gipa =
4609                                (PFN_vkGetInstanceProcAddr)loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr");
4610                            layer_prop->functions.get_instance_proc_addr = cur_gipa;
4611
4612                            if (NULL == cur_gipa) {
4613                                loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_LAYER_BIT, 0,
4614                                           "loader_create_instance_chain: Failed to find \'vkGetInstanceProcAddr\' in layer \"%s\"",
4615                                           layer_prop->lib_name);
4616                                continue;
4617                            }
4618                        } else {
4619                            cur_gipa = (PFN_vkGetInstanceProcAddr)loader_platform_get_proc_address(lib_handle,
4620                                                                                                   layer_prop->functions.str_gipa);
4621
4622                            if (NULL == cur_gipa) {
4623                                loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_LAYER_BIT, 0,
4624                                           "loader_create_instance_chain: Failed to find \'%s\' in layer \"%s\"",
4625                                           layer_prop->functions.str_gipa, layer_prop->lib_name);
4626                                continue;
4627                            }
4628                        }
4629                    }
4630                }
4631            }
4632
4633            layer_instance_link_info[num_activated_layers].pNext = chain_info.u.pLayerInfo;
4634            layer_instance_link_info[num_activated_layers].pfnNextGetInstanceProcAddr = next_gipa;
4635            layer_instance_link_info[num_activated_layers].pfnNextGetPhysicalDeviceProcAddr = next_gpdpa;
4636            next_gipa = cur_gipa;
4637            if (layer_prop->interface_version > 1 && cur_gpdpa != NULL) {
4638                layer_prop->functions.get_physical_device_proc_addr = cur_gpdpa;
4639                next_gpdpa = cur_gpdpa;
4640            }
4641            if (layer_prop->interface_version > 1 && cur_gipa != NULL) {
4642                layer_prop->functions.get_instance_proc_addr = cur_gipa;
4643            }
4644            if (layer_prop->interface_version > 1 && cur_gdpa != NULL) {
4645                layer_prop->functions.get_device_proc_addr = cur_gdpa;
4646            }
4647
4648            chain_info.u.pLayerInfo = &layer_instance_link_info[num_activated_layers];
4649
4650            activated_layers[num_activated_layers].name = layer_prop->info.layerName;
4651            activated_layers[num_activated_layers].manifest = layer_prop->manifest_file_name;
4652            activated_layers[num_activated_layers].library = layer_prop->lib_name;
4653            activated_layers[num_activated_layers].is_implicit = !(layer_prop->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER);
4654            if (activated_layers[num_activated_layers].is_implicit) {
4655                activated_layers[num_activated_layers].disable_env = layer_prop->disable_env_var.name;
4656            }
4657
4658            loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_LAYER_BIT, 0, "Insert instance layer \"%s\" (%s)",
4659                       layer_prop->info.layerName, layer_prop->lib_name);
4660
4661            num_activated_layers++;
4662        }
4663    }
4664
4665    // Make sure each layer requested by the application was actually loaded
4666    for (uint32_t exp = 0; exp < inst->expanded_activated_layer_list.count; ++exp) {
4667        struct loader_layer_properties *exp_layer_prop = inst->expanded_activated_layer_list.list[exp];
4668        bool found = false;
4669        for (uint32_t act = 0; act < num_activated_layers; ++act) {
4670            if (!strcmp(activated_layers[act].name, exp_layer_prop->info.layerName)) {
4671                found = true;
4672                break;
4673            }
4674        }
4675        // If it wasn't found, we want to at least log an error.  However, if it was enabled by the application directly,
4676        // we want to return a bad layer error.
4677        if (!found) {
4678            bool app_requested = false;
4679            for (uint32_t act = 0; act < pCreateInfo->enabledLayerCount; ++act) {
4680                if (!strcmp(pCreateInfo->ppEnabledLayerNames[act], exp_layer_prop->info.layerName)) {
4681                    app_requested = true;
4682                    break;
4683                }
4684            }
4685            VkFlags log_flag = VULKAN_LOADER_LAYER_BIT;
4686            char ending = '.';
4687            if (app_requested) {
4688                log_flag |= VULKAN_LOADER_ERROR_BIT;
4689                ending = '!';
4690            } else {
4691                log_flag |= VULKAN_LOADER_INFO_BIT;
4692            }
4693            switch (exp_layer_prop->lib_status) {
4694                case LOADER_LAYER_LIB_NOT_LOADED:
4695                    loader_log(inst, log_flag, 0, "Requested layer \"%s\" was not loaded%c", exp_layer_prop->info.layerName,
4696                               ending);
4697                    break;
4698                case LOADER_LAYER_LIB_ERROR_WRONG_BIT_TYPE: {
4699                    loader_log(inst, log_flag, 0, "Requested layer \"%s\" was wrong bit-type%c", exp_layer_prop->info.layerName,
4700                               ending);
4701                    break;
4702                }
4703                case LOADER_LAYER_LIB_ERROR_FAILED_TO_LOAD:
4704                    loader_log(inst, log_flag, 0, "Requested layer \"%s\" failed to load%c", exp_layer_prop->info.layerName,
4705                               ending);
4706                    break;
4707                case LOADER_LAYER_LIB_SUCCESS_LOADED:
4708                case LOADER_LAYER_LIB_ERROR_OUT_OF_MEMORY:
4709                    // Shouldn't be able to reach this but if it is, best to report a debug
4710                    loader_log(inst, log_flag, 0,
4711                               "Shouldn't reach this. A valid version of requested layer %s was loaded but was not found in the "
4712                               "list of activated layers%c",
4713                               exp_layer_prop->info.layerName, ending);
4714                    break;
4715            }
4716            if (app_requested) {
4717                return VK_ERROR_LAYER_NOT_PRESENT;
4718            }
4719        }
4720    }
4721
4722    VkLoaderFeatureFlags feature_flags = 0;
4723#if defined(_WIN32)
4724    feature_flags = windows_initialize_dxgi();
4725#endif
4726
4727    PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)next_gipa(*created_instance, "vkCreateInstance");
4728    if (fpCreateInstance) {
4729        VkLayerInstanceCreateInfo instance_dispatch;
4730        instance_dispatch.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO;
4731        instance_dispatch.pNext = loader_create_info.pNext;
4732        instance_dispatch.function = VK_LOADER_DATA_CALLBACK;
4733        instance_dispatch.u.pfnSetInstanceLoaderData = vkSetInstanceDispatch;
4734
4735        VkLayerInstanceCreateInfo device_callback;
4736        device_callback.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO;
4737        device_callback.pNext = &instance_dispatch;
4738        device_callback.function = VK_LOADER_LAYER_CREATE_DEVICE_CALLBACK;
4739        device_callback.u.layerDevice.pfnLayerCreateDevice = loader_layer_create_device;
4740        device_callback.u.layerDevice.pfnLayerDestroyDevice = loader_layer_destroy_device;
4741
4742        VkLayerInstanceCreateInfo loader_features;
4743        loader_features.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO;
4744        loader_features.pNext = &device_callback;
4745        loader_features.function = VK_LOADER_FEATURES;
4746        loader_features.u.loaderFeatures = feature_flags;
4747
4748        loader_create_info.pNext = &loader_features;
4749
4750        // If layer debugging is enabled, let's print out the full callstack with layers in their
4751        // defined order.
4752        loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, "vkCreateInstance layer callstack setup to:");
4753        loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, "   <Application>");
4754        loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, "     ||");
4755        loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, "   <Loader>");
4756        loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, "     ||");
4757        for (uint32_t cur_layer = 0; cur_layer < num_activated_layers; ++cur_layer) {
4758            uint32_t index = num_activated_layers - cur_layer - 1;
4759            loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, "   %s", activated_layers[index].name);
4760            loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, "           Type: %s",
4761                       activated_layers[index].is_implicit ? "Implicit" : "Explicit");
4762            if (activated_layers[index].is_implicit) {
4763                loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, "               Disable Env Var:  %s",
4764                           activated_layers[index].disable_env);
4765            }
4766            loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, "           Manifest: %s", activated_layers[index].manifest);
4767            loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, "           Library:  %s", activated_layers[index].library);
4768            loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, "     ||");
4769        }
4770        loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, "   <Drivers>");
4771
4772        res = fpCreateInstance(&loader_create_info, pAllocator, created_instance);
4773    } else {
4774        loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "loader_create_instance_chain: Failed to find \'vkCreateInstance\'");
4775        // Couldn't find CreateInstance function!
4776        res = VK_ERROR_INITIALIZATION_FAILED;
4777    }
4778
4779    if (res == VK_SUCCESS) {
4780        // Copy the current disp table into the terminator_dispatch table so we can use it in loader_gpa_instance_terminator()
4781        memcpy(&inst->terminator_dispatch, &inst->disp->layer_inst_disp, sizeof(VkLayerInstanceDispatchTable));
4782
4783        loader_init_instance_core_dispatch_table(&inst->disp->layer_inst_disp, next_gipa, *created_instance);
4784        inst->instance = *created_instance;
4785
4786        if (pCreateInfo->enabledLayerCount > 0 && pCreateInfo->ppEnabledLayerNames != NULL) {
4787            res = create_string_list(inst, pCreateInfo->enabledLayerCount, &inst->enabled_layer_names);
4788            if (res != VK_SUCCESS) {
4789                return res;
4790            }
4791
4792            for (uint32_t i = 0; i < pCreateInfo->enabledLayerCount; ++i) {
4793                res = copy_str_to_string_list(inst, &inst->enabled_layer_names, pCreateInfo->ppEnabledLayerNames[i],
4794                                              strlen(pCreateInfo->ppEnabledLayerNames[i]));
4795                if (res != VK_SUCCESS) return res;
4796            }
4797        }
4798    }
4799
4800    return res;
4801}
4802
4803void loader_activate_instance_layer_extensions(struct loader_instance *inst, VkInstance created_inst) {
4804    loader_init_instance_extension_dispatch_table(&inst->disp->layer_inst_disp, inst->disp->layer_inst_disp.GetInstanceProcAddr,
4805                                                  created_inst);
4806}
4807
4808#if defined(__APPLE__)
4809VkResult loader_create_device_chain(const VkPhysicalDevice pd, const VkDeviceCreateInfo *pCreateInfo,
4810                                    const VkAllocationCallbacks *pAllocator, const struct loader_instance *inst,
4811                                    struct loader_device *dev, PFN_vkGetInstanceProcAddr callingLayer,
4812                                    PFN_vkGetDeviceProcAddr *layerNextGDPA) __attribute__((optnone)) {
4813#else
4814VkResult loader_create_device_chain(const VkPhysicalDevice pd, const VkDeviceCreateInfo *pCreateInfo,
4815                                    const VkAllocationCallbacks *pAllocator, const struct loader_instance *inst,
4816                                    struct loader_device *dev, PFN_vkGetInstanceProcAddr callingLayer,
4817                                    PFN_vkGetDeviceProcAddr *layerNextGDPA) {
4818#endif
4819    uint32_t num_activated_layers = 0;
4820    struct activated_layer_info *activated_layers = NULL;
4821    VkLayerDeviceLink *layer_device_link_info;
4822    VkLayerDeviceCreateInfo chain_info;
4823    VkDeviceCreateInfo loader_create_info;
4824    VkDeviceGroupDeviceCreateInfo *original_device_group_create_info_struct = NULL;
4825    VkResult res;
4826
4827    PFN_vkGetDeviceProcAddr fpGDPA = NULL, nextGDPA = loader_gpa_device_terminator;
4828    PFN_vkGetInstanceProcAddr fpGIPA = NULL, nextGIPA = loader_gpa_instance_terminator;
4829
4830    memcpy(&loader_create_info, pCreateInfo, sizeof(VkDeviceCreateInfo));
4831
4832    if (loader_create_info.enabledLayerCount > 0 && loader_create_info.ppEnabledLayerNames != NULL) {
4833        bool invalid_device_layer_usage = false;
4834
4835        if (loader_create_info.enabledLayerCount != inst->enabled_layer_names.count && loader_create_info.enabledLayerCount > 0) {
4836            invalid_device_layer_usage = true;
4837        } else if (loader_create_info.enabledLayerCount > 0 && loader_create_info.ppEnabledLayerNames == NULL) {
4838            invalid_device_layer_usage = true;
4839        } else if (loader_create_info.enabledLayerCount == 0 && loader_create_info.ppEnabledLayerNames != NULL) {
4840            invalid_device_layer_usage = true;
4841        } else if (inst->enabled_layer_names.list != NULL) {
4842            for (uint32_t i = 0; i < loader_create_info.enabledLayerCount; i++) {
4843                const char *device_layer_names = loader_create_info.ppEnabledLayerNames[i];
4844
4845                if (strcmp(device_layer_names, inst->enabled_layer_names.list[i]) != 0) {
4846                    invalid_device_layer_usage = true;
4847                    break;
4848                }
4849            }
4850        }
4851
4852        if (invalid_device_layer_usage) {
4853            loader_log(
4854                inst, VULKAN_LOADER_WARN_BIT, 0,
4855                "loader_create_device_chain: Using deprecated and ignored 'ppEnabledLayerNames' member of 'VkDeviceCreateInfo' "
4856                "when creating a Vulkan device.");
4857        }
4858    }
4859
4860    // Before we continue, we need to find out if the KHR_device_group extension is in the enabled list.  If it is, we then
4861    // need to look for the corresponding VkDeviceGroupDeviceCreateInfo struct in the device list.  This is because we
4862    // need to replace all the incoming physical device values (which are really loader trampoline physical device values)
4863    // with the layer/ICD version.
4864    {
4865        VkBaseOutStructure *pNext = (VkBaseOutStructure *)loader_create_info.pNext;
4866        VkBaseOutStructure *pPrev = (VkBaseOutStructure *)&loader_create_info;
4867        while (NULL != pNext) {
4868            if (VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO == pNext->sType) {
4869                VkDeviceGroupDeviceCreateInfo *cur_struct = (VkDeviceGroupDeviceCreateInfo *)pNext;
4870                if (0 < cur_struct->physicalDeviceCount && NULL != cur_struct->pPhysicalDevices) {
4871                    VkDeviceGroupDeviceCreateInfo *temp_struct = loader_stack_alloc(sizeof(VkDeviceGroupDeviceCreateInfo));
4872                    VkPhysicalDevice *phys_dev_array = NULL;
4873                    if (NULL == temp_struct) {
4874                        return VK_ERROR_OUT_OF_HOST_MEMORY;
4875                    }
4876                    memcpy(temp_struct, cur_struct, sizeof(VkDeviceGroupDeviceCreateInfo));
4877                    phys_dev_array = loader_stack_alloc(sizeof(VkPhysicalDevice) * cur_struct->physicalDeviceCount);
4878                    if (NULL == phys_dev_array) {
4879                        return VK_ERROR_OUT_OF_HOST_MEMORY;
4880                    }
4881
4882                    // Before calling down, replace the incoming physical device values (which are really loader trampoline
4883                    // physical devices) with the next layer (or possibly even the terminator) physical device values.
4884                    struct loader_physical_device_tramp *cur_tramp;
4885                    for (uint32_t phys_dev = 0; phys_dev < cur_struct->physicalDeviceCount; phys_dev++) {
4886                        cur_tramp = (struct loader_physical_device_tramp *)cur_struct->pPhysicalDevices[phys_dev];
4887                        phys_dev_array[phys_dev] = cur_tramp->phys_dev;
4888                    }
4889                    temp_struct->pPhysicalDevices = phys_dev_array;
4890
4891                    original_device_group_create_info_struct = (VkDeviceGroupDeviceCreateInfo *)pPrev->pNext;
4892
4893                    // Replace the old struct in the pNext chain with this one.
4894                    pPrev->pNext = (VkBaseOutStructure *)temp_struct;
4895                }
4896                break;
4897            }
4898
4899            pPrev = pNext;
4900            pNext = pNext->pNext;
4901        }
4902    }
4903    if (inst->expanded_activated_layer_list.count > 0) {
4904        layer_device_link_info = loader_stack_alloc(sizeof(VkLayerDeviceLink) * inst->expanded_activated_layer_list.count);
4905        if (!layer_device_link_info) {
4906            loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
4907                       "loader_create_device_chain: Failed to alloc Device objects for layer. Skipping Layer.");
4908            return VK_ERROR_OUT_OF_HOST_MEMORY;
4909        }
4910
4911        activated_layers = loader_stack_alloc(sizeof(struct activated_layer_info) * inst->expanded_activated_layer_list.count);
4912        if (!activated_layers) {
4913            loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
4914                       "loader_create_device_chain: Failed to alloc activated layer storage array");
4915            return VK_ERROR_OUT_OF_HOST_MEMORY;
4916        }
4917
4918        chain_info.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO;
4919        chain_info.function = VK_LAYER_LINK_INFO;
4920        chain_info.u.pLayerInfo = NULL;
4921        chain_info.pNext = loader_create_info.pNext;
4922        loader_create_info.pNext = &chain_info;
4923
4924        // Create instance chain of enabled layers
4925        for (int32_t i = inst->expanded_activated_layer_list.count - 1; i >= 0; i--) {
4926            struct loader_layer_properties *layer_prop = inst->expanded_activated_layer_list.list[i];
4927            loader_platform_dl_handle lib_handle = layer_prop->lib_handle;
4928
4929            // Skip it if a Layer with the same name has been already successfully activated
4930            if (loader_names_array_has_layer_property(&layer_prop->info, num_activated_layers, activated_layers)) {
4931                continue;
4932            }
4933
4934            // Skip the layer if the handle is NULL - this is likely because the library failed to load but wasn't removed from
4935            // the list.
4936            if (!lib_handle) {
4937                continue;
4938            }
4939
4940            // The Get*ProcAddr pointers will already be filled in if they were received from either the json file or the
4941            // version negotiation
4942            if ((fpGIPA = layer_prop->functions.get_instance_proc_addr) == NULL) {
4943                if (layer_prop->functions.str_gipa == NULL || strlen(layer_prop->functions.str_gipa) == 0) {
4944                    fpGIPA = (PFN_vkGetInstanceProcAddr)loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr");
4945                    layer_prop->functions.get_instance_proc_addr = fpGIPA;
4946                } else
4947                    fpGIPA =
4948                        (PFN_vkGetInstanceProcAddr)loader_platform_get_proc_address(lib_handle, layer_prop->functions.str_gipa);
4949                if (!fpGIPA) {
4950                    loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_LAYER_BIT, 0,
4951                               "loader_create_device_chain: Failed to find \'vkGetInstanceProcAddr\' in layer \"%s\".  "
4952                               "Skipping layer.",
4953                               layer_prop->lib_name);
4954                    continue;
4955                }
4956            }
4957
4958            if (fpGIPA == callingLayer) {
4959                if (layerNextGDPA != NULL) {
4960                    *layerNextGDPA = nextGDPA;
4961                }
4962                // Break here because if fpGIPA is the same as callingLayer, that means a layer is trying to create a device,
4963                // and once we don't want to continue any further as the next layer will be the calling layer
4964                break;
4965            }
4966
4967            if ((fpGDPA = layer_prop->functions.get_device_proc_addr) == NULL) {
4968                if (layer_prop->functions.str_gdpa == NULL || strlen(layer_prop->functions.str_gdpa) == 0) {
4969                    fpGDPA = (PFN_vkGetDeviceProcAddr)loader_platform_get_proc_address(lib_handle, "vkGetDeviceProcAddr");
4970                    layer_prop->functions.get_device_proc_addr = fpGDPA;
4971                } else
4972                    fpGDPA = (PFN_vkGetDeviceProcAddr)loader_platform_get_proc_address(lib_handle, layer_prop->functions.str_gdpa);
4973                if (!fpGDPA) {
4974                    loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_LAYER_BIT, 0,
4975                               "Failed to find vkGetDeviceProcAddr in layer \"%s\"", layer_prop->lib_name);
4976                    continue;
4977                }
4978            }
4979
4980            layer_device_link_info[num_activated_layers].pNext = chain_info.u.pLayerInfo;
4981            layer_device_link_info[num_activated_layers].pfnNextGetInstanceProcAddr = nextGIPA;
4982            layer_device_link_info[num_activated_layers].pfnNextGetDeviceProcAddr = nextGDPA;
4983            chain_info.u.pLayerInfo = &layer_device_link_info[num_activated_layers];
4984            nextGIPA = fpGIPA;
4985            nextGDPA = fpGDPA;
4986
4987            activated_layers[num_activated_layers].name = layer_prop->info.layerName;
4988            activated_layers[num_activated_layers].manifest = layer_prop->manifest_file_name;
4989            activated_layers[num_activated_layers].library = layer_prop->lib_name;
4990            activated_layers[num_activated_layers].is_implicit = !(layer_prop->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER);
4991            if (activated_layers[num_activated_layers].is_implicit) {
4992                activated_layers[num_activated_layers].disable_env = layer_prop->disable_env_var.name;
4993            }
4994
4995            loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_LAYER_BIT, 0, "Inserted device layer \"%s\" (%s)",
4996                       layer_prop->info.layerName, layer_prop->lib_name);
4997
4998            num_activated_layers++;
4999        }
5000    }
5001
5002    VkDevice created_device = (VkDevice)dev;
5003    PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)nextGIPA(inst->instance, "vkCreateDevice");
5004    if (fpCreateDevice) {
5005        VkLayerDeviceCreateInfo create_info_disp;
5006
5007        create_info_disp.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO;
5008        create_info_disp.function = VK_LOADER_DATA_CALLBACK;
5009
5010        create_info_disp.u.pfnSetDeviceLoaderData = vkSetDeviceDispatch;
5011
5012        // If layer debugging is enabled, let's print out the full callstack with layers in their
5013        // defined order.
5014        uint32_t layer_driver_bits = VULKAN_LOADER_LAYER_BIT | VULKAN_LOADER_DRIVER_BIT;
5015        loader_log(inst, layer_driver_bits, 0, "vkCreateDevice layer callstack setup to:");
5016        loader_log(inst, layer_driver_bits, 0, "   <Application>");
5017        loader_log(inst, layer_driver_bits, 0, "     ||");
5018        loader_log(inst, layer_driver_bits, 0, "   <Loader>");
5019        loader_log(inst, layer_driver_bits, 0, "     ||");
5020        for (uint32_t cur_layer = 0; cur_layer < num_activated_layers; ++cur_layer) {
5021            uint32_t index = num_activated_layers - cur_layer - 1;
5022            loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, "   %s", activated_layers[index].name);
5023            loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, "           Type: %s",
5024                       activated_layers[index].is_implicit ? "Implicit" : "Explicit");
5025            if (activated_layers[index].is_implicit) {
5026                loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, "               Disable Env Var:  %s",
5027                           activated_layers[index].disable_env);
5028            }
5029            loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, "           Manifest: %s", activated_layers[index].manifest);
5030            loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, "           Library:  %s", activated_layers[index].library);
5031            loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, "     ||");
5032        }
5033        loader_log(inst, layer_driver_bits, 0, "   <Device>");
5034        create_info_disp.pNext = loader_create_info.pNext;
5035        loader_create_info.pNext = &create_info_disp;
5036        res = fpCreateDevice(pd, &loader_create_info, pAllocator, &created_device);
5037        if (res != VK_SUCCESS) {
5038            return res;
5039        }
5040        dev->chain_device = created_device;
5041
5042        // Because we changed the pNext chain to use our own VkDeviceGroupDeviceCreateInfo, we need to fixup the chain to
5043        // point back at the original VkDeviceGroupDeviceCreateInfo.
5044        VkBaseOutStructure *pNext = (VkBaseOutStructure *)loader_create_info.pNext;
5045        VkBaseOutStructure *pPrev = (VkBaseOutStructure *)&loader_create_info;
5046        while (NULL != pNext) {
5047            if (VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO == pNext->sType) {
5048                VkDeviceGroupDeviceCreateInfo *cur_struct = (VkDeviceGroupDeviceCreateInfo *)pNext;
5049                if (0 < cur_struct->physicalDeviceCount && NULL != cur_struct->pPhysicalDevices) {
5050                    pPrev->pNext = (VkBaseOutStructure *)original_device_group_create_info_struct;
5051                }
5052                break;
5053            }
5054
5055            pPrev = pNext;
5056            pNext = pNext->pNext;
5057        }
5058
5059    } else {
5060        loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
5061                   "loader_create_device_chain: Failed to find \'vkCreateDevice\' in layers or ICD");
5062        // Couldn't find CreateDevice function!
5063        return VK_ERROR_INITIALIZATION_FAILED;
5064    }
5065
5066    // Initialize device dispatch table
5067    loader_init_device_dispatch_table(&dev->loader_dispatch, nextGDPA, dev->chain_device);
5068    // Initialize the dispatch table to functions which need terminators
5069    // These functions point directly to the driver, not the terminator functions
5070    init_extension_device_proc_terminator_dispatch(dev);
5071
5072    return res;
5073}
5074
5075VkResult loader_validate_layers(const struct loader_instance *inst, const uint32_t layer_count,
5076                                const char *const *ppEnabledLayerNames, const struct loader_layer_list *list) {
5077    struct loader_layer_properties *prop;
5078
5079    if (layer_count > 0 && ppEnabledLayerNames == NULL) {
5080        loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
5081                   "loader_validate_layers: ppEnabledLayerNames is NULL but enabledLayerCount is greater than zero");
5082        return VK_ERROR_LAYER_NOT_PRESENT;
5083    }
5084
5085    for (uint32_t i = 0; i < layer_count; i++) {
5086        VkStringErrorFlags result = vk_string_validate(MaxLoaderStringLength, ppEnabledLayerNames[i]);
5087        if (result != VK_STRING_ERROR_NONE) {
5088            loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
5089                       "loader_validate_layers: ppEnabledLayerNames contains string that is too long or is badly formed");
5090            return VK_ERROR_LAYER_NOT_PRESENT;
5091        }
5092
5093        prop = loader_find_layer_property(ppEnabledLayerNames[i], list);
5094        if (NULL == prop) {
5095            loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
5096                       "loader_validate_layers: Layer %d does not exist in the list of available layers", i);
5097            return VK_ERROR_LAYER_NOT_PRESENT;
5098        }
5099        if (inst->settings.settings_active && prop->settings_control_value != LOADER_SETTINGS_LAYER_CONTROL_ON &&
5100            prop->settings_control_value != LOADER_SETTINGS_LAYER_CONTROL_DEFAULT) {
5101            loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
5102                       "loader_validate_layers: Layer %d was explicitly prevented from being enabled by the loader settings file",
5103                       i);
5104            return VK_ERROR_LAYER_NOT_PRESENT;
5105        }
5106    }
5107    return VK_SUCCESS;
5108}
5109
5110VkResult loader_validate_instance_extensions(struct loader_instance *inst, const struct loader_extension_list *icd_exts,
5111                                             const struct loader_layer_list *instance_layers,
5112                                             const struct loader_envvar_all_filters *layer_filters,
5113                                             const VkInstanceCreateInfo *pCreateInfo) {
5114    VkExtensionProperties *extension_prop;
5115    char *env_value;
5116    bool check_if_known = true;
5117    VkResult res = VK_SUCCESS;
5118
5119    struct loader_pointer_layer_list active_layers = {0};
5120    struct loader_pointer_layer_list expanded_layers = {0};
5121
5122    if (pCreateInfo->enabledExtensionCount > 0 && pCreateInfo->ppEnabledExtensionNames == NULL) {
5123        loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
5124                   "loader_validate_instance_extensions: Instance ppEnabledExtensionNames is NULL but enabledExtensionCount is "
5125                   "greater than zero");
5126        return VK_ERROR_EXTENSION_NOT_PRESENT;
5127    }
5128    if (!loader_init_pointer_layer_list(inst, &active_layers)) {
5129        res = VK_ERROR_OUT_OF_HOST_MEMORY;
5130        goto out;
5131    }
5132    if (!loader_init_pointer_layer_list(inst, &expanded_layers)) {
5133        res = VK_ERROR_OUT_OF_HOST_MEMORY;
5134        goto out;
5135    }
5136
5137    if (inst->settings.settings_active) {
5138        res = enable_correct_layers_from_settings(inst, layer_filters, pCreateInfo->enabledLayerCount,
5139                                                  pCreateInfo->ppEnabledLayerNames, instance_layers, &active_layers,
5140                                                  &expanded_layers);
5141        if (res != VK_SUCCESS) {
5142            goto out;
5143        }
5144    } else {
5145        // Build the lists of active layers (including meta layers) and expanded layers (with meta layers resolved to their
5146        // components)
5147        res = loader_add_implicit_layers(inst, layer_filters, &active_layers, &expanded_layers, instance_layers);
5148        if (res != VK_SUCCESS) {
5149            goto out;
5150        }
5151        res = loader_add_environment_layers(inst, VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER, layer_filters, &active_layers,
5152                                            &expanded_layers, instance_layers);
5153        if (res != VK_SUCCESS) {
5154            goto out;
5155        }
5156        res = loader_add_layer_names_to_list(inst, layer_filters, &active_layers, &expanded_layers, pCreateInfo->enabledLayerCount,
5157                                             pCreateInfo->ppEnabledLayerNames, instance_layers);
5158        if (VK_SUCCESS != res) {
5159            goto out;
5160        }
5161    }
5162    for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
5163        VkStringErrorFlags result = vk_string_validate(MaxLoaderStringLength, pCreateInfo->ppEnabledExtensionNames[i]);
5164        if (result != VK_STRING_ERROR_NONE) {
5165            loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
5166                       "loader_validate_instance_extensions: Instance ppEnabledExtensionNames contains "
5167                       "string that is too long or is badly formed");
5168            res = VK_ERROR_EXTENSION_NOT_PRESENT;
5169            goto out;
5170        }
5171
5172        // Check if a user wants to disable the instance extension filtering behavior
5173        env_value = loader_getenv("VK_LOADER_DISABLE_INST_EXT_FILTER", inst);
5174        if (NULL != env_value && atoi(env_value) != 0) {
5175            check_if_known = false;
5176        }
5177        loader_free_getenv(env_value, inst);
5178
5179        if (check_if_known) {
5180            // See if the extension is in the list of supported extensions
5181            bool found = false;
5182            for (uint32_t j = 0; LOADER_INSTANCE_EXTENSIONS[j] != NULL; j++) {
5183                if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], LOADER_INSTANCE_EXTENSIONS[j]) == 0) {
5184                    found = true;
5185                    break;
5186                }
5187            }
5188
5189            // If it isn't in the list, return an error
5190            if (!found) {
5191                loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
5192                           "loader_validate_instance_extensions: Extension %s not found in list of known instance extensions.",
5193                           pCreateInfo->ppEnabledExtensionNames[i]);
5194                res = VK_ERROR_EXTENSION_NOT_PRESENT;
5195                goto out;
5196            }
5197        }
5198
5199        extension_prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i], icd_exts);
5200
5201        if (extension_prop) {
5202            continue;
5203        }
5204
5205        extension_prop = NULL;
5206
5207        // Not in global list, search layer extension lists
5208        for (uint32_t j = 0; NULL == extension_prop && j < expanded_layers.count; ++j) {
5209            extension_prop =
5210                get_extension_property(pCreateInfo->ppEnabledExtensionNames[i], &expanded_layers.list[j]->instance_extension_list);
5211            if (extension_prop) {
5212                // Found the extension in one of the layers enabled by the app.
5213                break;
5214            }
5215
5216            struct loader_layer_properties *layer_prop =
5217                loader_find_layer_property(expanded_layers.list[j]->info.layerName, instance_layers);
5218            if (NULL == layer_prop) {
5219                // Should NOT get here, loader_validate_layers should have already filtered this case out.
5220                continue;
5221            }
5222        }
5223
5224        if (!extension_prop) {
5225            // Didn't find extension name in any of the global layers, error out
5226            loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
5227                       "loader_validate_instance_extensions: Instance extension %s not supported by available ICDs or enabled "
5228                       "layers.",
5229                       pCreateInfo->ppEnabledExtensionNames[i]);
5230            res = VK_ERROR_EXTENSION_NOT_PRESENT;
5231            goto out;
5232        }
5233    }
5234
5235out:
5236    loader_destroy_pointer_layer_list(inst, &active_layers);
5237    loader_destroy_pointer_layer_list(inst, &expanded_layers);
5238    return res;
5239}
5240
5241VkResult loader_validate_device_extensions(struct loader_instance *this_instance,
5242                                           const struct loader_pointer_layer_list *activated_device_layers,
5243                                           const struct loader_extension_list *icd_exts, const VkDeviceCreateInfo *pCreateInfo) {
5244    for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
5245        VkStringErrorFlags result = vk_string_validate(MaxLoaderStringLength, pCreateInfo->ppEnabledExtensionNames[i]);
5246        if (result != VK_STRING_ERROR_NONE) {
5247            loader_log(this_instance, VULKAN_LOADER_ERROR_BIT, 0,
5248                       "loader_validate_device_extensions: Device ppEnabledExtensionNames contains "
5249                       "string that is too long or is badly formed");
5250            return VK_ERROR_EXTENSION_NOT_PRESENT;
5251        }
5252
5253        const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
5254        VkExtensionProperties *extension_prop = get_extension_property(extension_name, icd_exts);
5255
5256        if (extension_prop) {
5257            continue;
5258        }
5259
5260        // Not in global list, search activated layer extension lists
5261        for (uint32_t j = 0; j < activated_device_layers->count; j++) {
5262            struct loader_layer_properties *layer_prop = activated_device_layers->list[j];
5263
5264            extension_prop = get_dev_extension_property(extension_name, &layer_prop->device_extension_list);
5265            if (extension_prop) {
5266                // Found the extension in one of the layers enabled by the app.
5267                break;
5268            }
5269        }
5270
5271        if (!extension_prop) {
5272            // Didn't find extension name in any of the device layers, error out
5273            loader_log(this_instance, VULKAN_LOADER_ERROR_BIT, 0,
5274                       "loader_validate_device_extensions: Device extension %s not supported by selected physical device "
5275                       "or enabled layers.",
5276                       pCreateInfo->ppEnabledExtensionNames[i]);
5277            return VK_ERROR_EXTENSION_NOT_PRESENT;
5278        }
5279    }
5280    return VK_SUCCESS;
5281}
5282
5283// Terminator functions for the Instance chain
5284// All named terminator_<Vulkan API name>
5285VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateInstance(const VkInstanceCreateInfo *pCreateInfo,
5286                                                         const VkAllocationCallbacks *pAllocator, VkInstance *pInstance) {
5287    struct loader_icd_term *icd_term;
5288    VkExtensionProperties *prop;
5289    char **filtered_extension_names = NULL;
5290    VkInstanceCreateInfo icd_create_info;
5291    VkResult res = VK_SUCCESS;
5292    bool one_icd_successful = false;
5293
5294    struct loader_instance *ptr_instance = (struct loader_instance *)*pInstance;
5295    if (NULL == ptr_instance) {
5296        loader_log(ptr_instance, VULKAN_LOADER_WARN_BIT, 0,
5297                   "terminator_CreateInstance: Loader instance pointer null encountered.  Possibly set by active layer. (Policy "
5298                   "#LLP_LAYER_21)");
5299    } else if (LOADER_MAGIC_NUMBER != ptr_instance->magic) {
5300        loader_log(ptr_instance, VULKAN_LOADER_WARN_BIT, 0,
5301                   "terminator_CreateInstance: Instance pointer (%p) has invalid MAGIC value 0x%08lx. Instance value possibly "
5302                   "corrupted by active layer (Policy #LLP_LAYER_21).  ",
5303                   ptr_instance, ptr_instance->magic);
5304    }
5305
5306    // Save the application version if it has been modified - layers sometimes needs features in newer API versions than
5307    // what the application requested, and thus will increase the instance version to a level that suites their needs.
5308    if (pCreateInfo->pApplicationInfo && pCreateInfo->pApplicationInfo->apiVersion) {
5309        loader_api_version altered_version = loader_make_version(pCreateInfo->pApplicationInfo->apiVersion);
5310        if (altered_version.major != ptr_instance->app_api_version.major ||
5311            altered_version.minor != ptr_instance->app_api_version.minor) {
5312            ptr_instance->app_api_version = altered_version;
5313        }
5314    }
5315
5316    memcpy(&icd_create_info, pCreateInfo, sizeof(icd_create_info));
5317
5318    icd_create_info.enabledLayerCount = 0;
5319    icd_create_info.ppEnabledLayerNames = NULL;
5320
5321    // NOTE: Need to filter the extensions to only those supported by the ICD.
5322    //       No ICD will advertise support for layers. An ICD library could
5323    //       support a layer, but it would be independent of the actual ICD,
5324    //       just in the same library.
5325    uint32_t extension_count = pCreateInfo->enabledExtensionCount;
5326#if defined(LOADER_ENABLE_LINUX_SORT)
5327    extension_count += 1;
5328#endif  // LOADER_ENABLE_LINUX_SORT
5329    filtered_extension_names = loader_stack_alloc(extension_count * sizeof(char *));
5330    if (!filtered_extension_names) {
5331        loader_log(ptr_instance, VULKAN_LOADER_ERROR_BIT, 0,
5332                   "terminator_CreateInstance: Failed create extension name array for %d extensions", extension_count);
5333        res = VK_ERROR_OUT_OF_HOST_MEMORY;
5334        goto out;
5335    }
5336    icd_create_info.ppEnabledExtensionNames = (const char *const *)filtered_extension_names;
5337
5338    // Determine if Get Physical Device Properties 2 is available to this Instance
5339    if (pCreateInfo->pApplicationInfo && pCreateInfo->pApplicationInfo->apiVersion >= VK_API_VERSION_1_1) {
5340        ptr_instance->supports_get_dev_prop_2 = true;
5341    } else {
5342        for (uint32_t j = 0; j < pCreateInfo->enabledExtensionCount; j++) {
5343            if (!strcmp(pCreateInfo->ppEnabledExtensionNames[j], VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
5344                ptr_instance->supports_get_dev_prop_2 = true;
5345                break;
5346            }
5347        }
5348    }
5349
5350    for (uint32_t i = 0; i < ptr_instance->icd_tramp_list.count; i++) {
5351        icd_term = loader_icd_add(ptr_instance, &ptr_instance->icd_tramp_list.scanned_list[i]);
5352        if (NULL == icd_term) {
5353            loader_log(ptr_instance, VULKAN_LOADER_ERROR_BIT, 0,
5354                       "terminator_CreateInstance: Failed to add ICD %d to ICD trampoline list.", i);
5355            res = VK_ERROR_OUT_OF_HOST_MEMORY;
5356            goto out;
5357        }
5358
5359        // If any error happens after here, we need to remove the ICD from the list,
5360        // because we've already added it, but haven't validated it
5361
5362        // Make sure that we reset the pApplicationInfo so we don't get an old pointer
5363        icd_create_info.pApplicationInfo = pCreateInfo->pApplicationInfo;
5364        icd_create_info.enabledExtensionCount = 0;
5365        struct loader_extension_list icd_exts = {0};
5366
5367        // traverse scanned icd list adding non-duplicate extensions to the list
5368        res = loader_init_generic_list(ptr_instance, (struct loader_generic_list *)&icd_exts, sizeof(VkExtensionProperties));
5369        if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
5370            // If out of memory, bail immediately.
5371            goto out;
5372        } else if (VK_SUCCESS != res) {
5373            // Something bad happened with this ICD, so free it and try the
5374            // next.
5375            ptr_instance->icd_terms = icd_term->next;
5376            icd_term->next = NULL;
5377            loader_icd_destroy(ptr_instance, icd_term, pAllocator);
5378            continue;
5379        }
5380
5381        res = loader_add_instance_extensions(ptr_instance, icd_term->scanned_icd->EnumerateInstanceExtensionProperties,
5382                                             icd_term->scanned_icd->lib_name, &icd_exts);
5383        if (VK_SUCCESS != res) {
5384            loader_destroy_generic_list(ptr_instance, (struct loader_generic_list *)&icd_exts);
5385            if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
5386                // If out of memory, bail immediately.
5387                goto out;
5388            } else {
5389                // Something bad happened with this ICD, so free it and try the next.
5390                ptr_instance->icd_terms = icd_term->next;
5391                icd_term->next = NULL;
5392                loader_icd_destroy(ptr_instance, icd_term, pAllocator);
5393                continue;
5394            }
5395        }
5396
5397        for (uint32_t j = 0; j < pCreateInfo->enabledExtensionCount; j++) {
5398            prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[j], &icd_exts);
5399            if (prop) {
5400                filtered_extension_names[icd_create_info.enabledExtensionCount] = (char *)pCreateInfo->ppEnabledExtensionNames[j];
5401                icd_create_info.enabledExtensionCount++;
5402            }
5403        }
5404#if defined(LOADER_ENABLE_LINUX_SORT)
5405        // Force on "VK_KHR_get_physical_device_properties2" for Linux as we use it for GPU sorting.  This
5406        // should be done if the API version of either the application or the driver does not natively support
5407        // the core version of vkGetPhysicalDeviceProperties2 entrypoint.
5408        if ((ptr_instance->app_api_version.major == 1 && ptr_instance->app_api_version.minor == 0) ||
5409            (VK_API_VERSION_MAJOR(icd_term->scanned_icd->api_version) == 1 &&
5410             VK_API_VERSION_MINOR(icd_term->scanned_icd->api_version) == 0)) {
5411            prop = get_extension_property(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, &icd_exts);
5412            if (prop) {
5413                filtered_extension_names[icd_create_info.enabledExtensionCount] =
5414                    (char *)VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME;
5415                icd_create_info.enabledExtensionCount++;
5416
5417                // At least one ICD supports this, so the instance should be able to support it
5418                ptr_instance->supports_get_dev_prop_2 = true;
5419            }
5420        }
5421#endif  // LOADER_ENABLE_LINUX_SORT
5422
5423        // Determine if vkGetPhysicalDeviceProperties2 is available to this Instance
5424        if (icd_term->scanned_icd->api_version >= VK_API_VERSION_1_1) {
5425            icd_term->supports_get_dev_prop_2 = true;
5426        } else {
5427            for (uint32_t j = 0; j < icd_create_info.enabledExtensionCount; j++) {
5428                if (!strcmp(filtered_extension_names[j], VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
5429                    icd_term->supports_get_dev_prop_2 = true;
5430                    break;
5431                }
5432            }
5433        }
5434
5435        loader_destroy_generic_list(ptr_instance, (struct loader_generic_list *)&icd_exts);
5436
5437        // Get the driver version from vkEnumerateInstanceVersion
5438        uint32_t icd_version = VK_API_VERSION_1_0;
5439        VkResult icd_result = VK_SUCCESS;
5440        if (icd_term->scanned_icd->api_version >= VK_API_VERSION_1_1) {
5441            PFN_vkEnumerateInstanceVersion icd_enumerate_instance_version =
5442                (PFN_vkEnumerateInstanceVersion)icd_term->scanned_icd->GetInstanceProcAddr(NULL, "vkEnumerateInstanceVersion");
5443            if (icd_enumerate_instance_version != NULL) {
5444                icd_result = icd_enumerate_instance_version(&icd_version);
5445                if (icd_result != VK_SUCCESS) {
5446                    icd_version = VK_API_VERSION_1_0;
5447                    loader_log(ptr_instance, VULKAN_LOADER_DEBUG_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
5448                               "terminator_CreateInstance: ICD \"%s\" vkEnumerateInstanceVersion returned error. The ICD will be "
5449                               "treated as a 1.0 ICD",
5450                               icd_term->scanned_icd->lib_name);
5451                } else if (VK_API_VERSION_MINOR(icd_version) == 0) {
5452                    loader_log(ptr_instance, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
5453                               "terminator_CreateInstance: Manifest ICD for \"%s\" contained a 1.1 or greater API version, but "
5454                               "vkEnumerateInstanceVersion returned 1.0, treating as a 1.0 ICD",
5455                               icd_term->scanned_icd->lib_name);
5456                }
5457            } else {
5458                loader_log(ptr_instance, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
5459                           "terminator_CreateInstance: Manifest ICD for \"%s\" contained a 1.1 or greater API version, but does "
5460                           "not support vkEnumerateInstanceVersion, treating as a 1.0 ICD",
5461                           icd_term->scanned_icd->lib_name);
5462            }
5463        }
5464
5465        // Remove the portability enumeration flag bit if the ICD doesn't support the extension
5466        if ((pCreateInfo->flags & VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR) == 1) {
5467            bool supports_portability_enumeration = false;
5468            for (uint32_t j = 0; j < icd_create_info.enabledExtensionCount; j++) {
5469                if (strcmp(filtered_extension_names[j], VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME) == 0) {
5470                    supports_portability_enumeration = true;
5471                    break;
5472                }
5473            }
5474            // If the icd supports the extension, use the flags as given, otherwise remove the portability bit
5475            icd_create_info.flags = supports_portability_enumeration
5476                                        ? pCreateInfo->flags
5477                                        : pCreateInfo->flags & (~VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR);
5478        }
5479
5480        // Create an instance, substituting the version to 1.0 if necessary
5481        VkApplicationInfo icd_app_info;
5482        const uint32_t api_variant = 0;
5483        const uint32_t api_version_1_0 = VK_API_VERSION_1_0;
5484        uint32_t icd_version_nopatch =
5485            VK_MAKE_API_VERSION(api_variant, VK_API_VERSION_MAJOR(icd_version), VK_API_VERSION_MINOR(icd_version), 0);
5486        uint32_t requested_version = (pCreateInfo == NULL || pCreateInfo->pApplicationInfo == NULL)
5487                                         ? api_version_1_0
5488                                         : pCreateInfo->pApplicationInfo->apiVersion;
5489        if ((requested_version != 0) && (icd_version_nopatch == api_version_1_0)) {
5490            if (icd_create_info.pApplicationInfo == NULL) {
5491                memset(&icd_app_info, 0, sizeof(icd_app_info));
5492            } else {
5493                memmove(&icd_app_info, icd_create_info.pApplicationInfo, sizeof(icd_app_info));
5494            }
5495            icd_app_info.apiVersion = icd_version;
5496            icd_create_info.pApplicationInfo = &icd_app_info;
5497        }
5498        icd_result =
5499            ptr_instance->icd_tramp_list.scanned_list[i].CreateInstance(&icd_create_info, pAllocator, &(icd_term->instance));
5500        if (VK_ERROR_OUT_OF_HOST_MEMORY == icd_result) {
5501            // If out of memory, bail immediately.
5502            res = VK_ERROR_OUT_OF_HOST_MEMORY;
5503            goto out;
5504        } else if (VK_SUCCESS != icd_result) {
5505            loader_log(ptr_instance, VULKAN_LOADER_WARN_BIT, 0,
5506                       "terminator_CreateInstance: Received return code %i from call to vkCreateInstance in ICD %s. Skipping "
5507                       "this driver.",
5508                       icd_result, icd_term->scanned_icd->lib_name);
5509            ptr_instance->icd_terms = icd_term->next;
5510            icd_term->next = NULL;
5511            loader_icd_destroy(ptr_instance, icd_term, pAllocator);
5512            continue;
5513        }
5514
5515        if (!loader_icd_init_entries(ptr_instance, icd_term)) {
5516            loader_log(ptr_instance, VULKAN_LOADER_WARN_BIT, 0,
5517                       "terminator_CreateInstance: Failed to find required entrypoints in ICD %s. Skipping this driver.",
5518                       icd_term->scanned_icd->lib_name);
5519            ptr_instance->icd_terms = icd_term->next;
5520            icd_term->next = NULL;
5521            loader_icd_destroy(ptr_instance, icd_term, pAllocator);
5522            continue;
5523        }
5524
5525        if (ptr_instance->icd_tramp_list.scanned_list[i].interface_version < 3 &&
5526            (
5527#if defined(VK_USE_PLATFORM_XLIB_KHR)
5528                NULL != icd_term->dispatch.CreateXlibSurfaceKHR ||
5529#endif  // VK_USE_PLATFORM_XLIB_KHR
5530#if defined(VK_USE_PLATFORM_XCB_KHR)
5531                NULL != icd_term->dispatch.CreateXcbSurfaceKHR ||
5532#endif  // VK_USE_PLATFORM_XCB_KHR
5533#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
5534                NULL != icd_term->dispatch.CreateWaylandSurfaceKHR ||
5535#endif  // VK_USE_PLATFORM_WAYLAND_KHR
5536#if defined(VK_USE_PLATFORM_ANDROID_KHR)
5537                NULL != icd_term->dispatch.CreateAndroidSurfaceKHR ||
5538#endif  // VK_USE_PLATFORM_ANDROID_KHR
5539#if defined(VK_USE_PLATFORM_OHOS)
5540                NULL != icd_term->dispatch.CreateSurfaceOHOS ||
5541#endif  // VK_USE_PLATFORM_OHOS
5542#if defined(VK_USE_PLATFORM_WIN32_KHR)
5543                NULL != icd_term->dispatch.CreateWin32SurfaceKHR ||
5544#endif  // VK_USE_PLATFORM_WIN32_KHR
5545                NULL != icd_term->dispatch.DestroySurfaceKHR)) {
5546            loader_log(ptr_instance, VULKAN_LOADER_WARN_BIT, 0,
5547                       "terminator_CreateInstance: Driver %s supports interface version %u but still exposes VkSurfaceKHR"
5548                       " create/destroy entrypoints (Policy #LDP_DRIVER_8)",
5549                       ptr_instance->icd_tramp_list.scanned_list[i].lib_name,
5550                       ptr_instance->icd_tramp_list.scanned_list[i].interface_version);
5551        }
5552
5553        // If we made it this far, at least one ICD was successful
5554        one_icd_successful = true;
5555    }
5556
5557    // For vkGetPhysicalDeviceProperties2, at least one ICD needs to support the extension for the
5558    // instance to have it
5559    if (ptr_instance->supports_get_dev_prop_2) {
5560        bool at_least_one_supports = false;
5561        icd_term = ptr_instance->icd_terms;
5562        while (icd_term != NULL) {
5563            if (icd_term->supports_get_dev_prop_2) {
5564                at_least_one_supports = true;
5565                break;
5566            }
5567            icd_term = icd_term->next;
5568        }
5569        if (!at_least_one_supports) {
5570            ptr_instance->supports_get_dev_prop_2 = false;
5571        }
5572    }
5573
5574    // If no ICDs were added to instance list and res is unchanged from it's initial value, the loader was unable to
5575    // find a suitable ICD.
5576    if (VK_SUCCESS == res && (ptr_instance->icd_terms == NULL || !one_icd_successful)) {
5577        loader_log(ptr_instance, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
5578                   "terminator_CreateInstance: Found no drivers!");
5579        res = VK_ERROR_INCOMPATIBLE_DRIVER;
5580    }
5581
5582out:
5583
5584    ptr_instance->create_terminator_invalid_extension = false;
5585
5586    if (VK_SUCCESS != res) {
5587        if (VK_ERROR_EXTENSION_NOT_PRESENT == res) {
5588            ptr_instance->create_terminator_invalid_extension = true;
5589        }
5590
5591        while (NULL != ptr_instance->icd_terms) {
5592            icd_term = ptr_instance->icd_terms;
5593            ptr_instance->icd_terms = icd_term->next;
5594            if (NULL != icd_term->instance) {
5595                icd_term->dispatch.DestroyInstance(icd_term->instance, pAllocator);
5596            }
5597            loader_icd_destroy(ptr_instance, icd_term, pAllocator);
5598        }
5599    } else {
5600        // Check for enabled extensions here to setup the loader structures so the loader knows what extensions
5601        // it needs to worry about.
5602        // We do it here and again above the layers in the trampoline function since the trampoline function
5603        // may think different extensions are enabled than what's down here.
5604        // This is why we don't clear inside of these function calls.
5605        // The clearing should actually be handled by the overall memset of the pInstance structure in the
5606        // trampoline.
5607        wsi_create_instance(ptr_instance, pCreateInfo);
5608        check_for_enabled_debug_extensions(ptr_instance, pCreateInfo);
5609        extensions_create_instance(ptr_instance, pCreateInfo);
5610    }
5611
5612    return res;
5613}
5614
5615VKAPI_ATTR void VKAPI_CALL terminator_DestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
5616    struct loader_instance *ptr_instance = loader_get_instance(instance);
5617    if (NULL == ptr_instance) {
5618        return;
5619    }
5620    struct loader_icd_term *icd_terms = ptr_instance->icd_terms;
5621    struct loader_icd_term *next_icd_term;
5622
5623    // Remove this instance from the list of instances:
5624    struct loader_instance *prev = NULL;
5625    loader_platform_thread_lock_mutex(&loader_global_instance_list_lock);
5626    struct loader_instance *next = loader.instances;
5627    while (next != NULL) {
5628        if (next == ptr_instance) {
5629            // Remove this instance from the list:
5630            if (prev)
5631                prev->next = next->next;
5632            else
5633                loader.instances = next->next;
5634            break;
5635        }
5636        prev = next;
5637        next = next->next;
5638    }
5639    loader_platform_thread_unlock_mutex(&loader_global_instance_list_lock);
5640
5641    while (NULL != icd_terms) {
5642        if (icd_terms->instance) {
5643            icd_terms->dispatch.DestroyInstance(icd_terms->instance, pAllocator);
5644        }
5645        next_icd_term = icd_terms->next;
5646        icd_terms->instance = VK_NULL_HANDLE;
5647        loader_icd_destroy(ptr_instance, icd_terms, pAllocator);
5648
5649        icd_terms = next_icd_term;
5650    }
5651
5652    loader_scanned_icd_clear(ptr_instance, &ptr_instance->icd_tramp_list);
5653    loader_destroy_generic_list(ptr_instance, (struct loader_generic_list *)&ptr_instance->ext_list);
5654    if (NULL != ptr_instance->phys_devs_term) {
5655        for (uint32_t i = 0; i < ptr_instance->phys_dev_count_term; i++) {
5656            for (uint32_t j = i + 1; j < ptr_instance->phys_dev_count_term; j++) {
5657                if (ptr_instance->phys_devs_term[i] == ptr_instance->phys_devs_term[j]) {
5658                    ptr_instance->phys_devs_term[j] = NULL;
5659                }
5660            }
5661        }
5662        for (uint32_t i = 0; i < ptr_instance->phys_dev_count_term; i++) {
5663            loader_instance_heap_free(ptr_instance, ptr_instance->phys_devs_term[i]);
5664        }
5665        loader_instance_heap_free(ptr_instance, ptr_instance->phys_devs_term);
5666    }
5667    if (NULL != ptr_instance->phys_dev_groups_term) {
5668        for (uint32_t i = 0; i < ptr_instance->phys_dev_group_count_term; i++) {
5669            loader_instance_heap_free(ptr_instance, ptr_instance->phys_dev_groups_term[i]);
5670        }
5671        loader_instance_heap_free(ptr_instance, ptr_instance->phys_dev_groups_term);
5672    }
5673    loader_free_dev_ext_table(ptr_instance);
5674    loader_free_phys_dev_ext_table(ptr_instance);
5675
5676    free_string_list(ptr_instance, &ptr_instance->enabled_layer_names);
5677}
5678
5679VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo,
5680                                                       const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
5681    VkResult res = VK_SUCCESS;
5682    struct loader_physical_device_term *phys_dev_term;
5683    phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
5684    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
5685
5686    struct loader_device *dev = (struct loader_device *)*pDevice;
5687    PFN_vkCreateDevice fpCreateDevice = icd_term->dispatch.CreateDevice;
5688    struct loader_extension_list icd_exts;
5689
5690    VkBaseOutStructure *caller_dgci_container = NULL;
5691    VkDeviceGroupDeviceCreateInfo *caller_dgci = NULL;
5692
5693    if (NULL == dev) {
5694        loader_log(icd_term->this_instance, VULKAN_LOADER_WARN_BIT, 0,
5695                   "terminator_CreateDevice: Loader device pointer null encountered.  Possibly set by active layer. (Policy "
5696                   "#LLP_LAYER_22)");
5697    } else if (DEVICE_DISP_TABLE_MAGIC_NUMBER != dev->loader_dispatch.core_dispatch.magic) {
5698        loader_log(icd_term->this_instance, VULKAN_LOADER_WARN_BIT, 0,
5699                   "terminator_CreateDevice: Device pointer (%p) has invalid MAGIC value 0x%08lx. The expected value is "
5700                   "0x10ADED040410ADED. Device value possibly "
5701                   "corrupted by active layer (Policy #LLP_LAYER_22).  ",
5702                   dev, dev->loader_dispatch.core_dispatch.magic);
5703    }
5704
5705    dev->phys_dev_term = phys_dev_term;
5706
5707    icd_exts.list = NULL;
5708
5709    if (fpCreateDevice == NULL) {
5710        loader_log(icd_term->this_instance, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
5711                   "terminator_CreateDevice: No vkCreateDevice command exposed by ICD %s", icd_term->scanned_icd->lib_name);
5712        res = VK_ERROR_INITIALIZATION_FAILED;
5713        goto out;
5714    }
5715
5716    VkDeviceCreateInfo localCreateInfo;
5717    memcpy(&localCreateInfo, pCreateInfo, sizeof(localCreateInfo));
5718
5719    // NOTE: Need to filter the extensions to only those supported by the ICD.
5720    //       No ICD will advertise support for layers. An ICD library could support a layer,
5721    //       but it would be independent of the actual ICD, just in the same library.
5722    char **filtered_extension_names = NULL;
5723    if (0 < pCreateInfo->enabledExtensionCount) {
5724        filtered_extension_names = loader_stack_alloc(pCreateInfo->enabledExtensionCount * sizeof(char *));
5725        if (NULL == filtered_extension_names) {
5726            loader_log(icd_term->this_instance, VULKAN_LOADER_ERROR_BIT, 0,
5727                       "terminator_CreateDevice: Failed to create extension name storage for %d extensions",
5728                       pCreateInfo->enabledExtensionCount);
5729            return VK_ERROR_OUT_OF_HOST_MEMORY;
5730        }
5731    }
5732
5733    localCreateInfo.enabledLayerCount = 0;
5734    localCreateInfo.ppEnabledLayerNames = NULL;
5735
5736    localCreateInfo.enabledExtensionCount = 0;
5737    localCreateInfo.ppEnabledExtensionNames = (const char *const *)filtered_extension_names;
5738
5739    // Get the physical device (ICD) extensions
5740    res = loader_init_generic_list(icd_term->this_instance, (struct loader_generic_list *)&icd_exts, sizeof(VkExtensionProperties));
5741    if (VK_SUCCESS != res) {
5742        goto out;
5743    }
5744
5745    res = loader_add_device_extensions(icd_term->this_instance, icd_term->dispatch.EnumerateDeviceExtensionProperties,
5746                                       phys_dev_term->phys_dev, icd_term->scanned_icd->lib_name, &icd_exts);
5747    if (res != VK_SUCCESS) {
5748        goto out;
5749    }
5750
5751    for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
5752        const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
5753        VkExtensionProperties *prop = get_extension_property(extension_name, &icd_exts);
5754        if (prop) {
5755            filtered_extension_names[localCreateInfo.enabledExtensionCount] = (char *)extension_name;
5756            localCreateInfo.enabledExtensionCount++;
5757        } else {
5758            loader_log(icd_term->this_instance, VULKAN_LOADER_DEBUG_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
5759                       "vkCreateDevice extension %s not available for devices associated with ICD %s", extension_name,
5760                       icd_term->scanned_icd->lib_name);
5761        }
5762    }
5763
5764    // Before we continue, If KHX_device_group is the list of enabled and viable extensions, then we then need to look for the
5765    // corresponding VkDeviceGroupDeviceCreateInfo struct in the device list and replace all the physical device values (which
5766    // are really loader physical device terminator values) with the ICD versions.
5767    // if (icd_term->this_instance->enabled_known_extensions.khr_device_group_creation == 1) {
5768    {
5769        VkBaseOutStructure *pNext = (VkBaseOutStructure *)localCreateInfo.pNext;
5770        VkBaseOutStructure *pPrev = (VkBaseOutStructure *)&localCreateInfo;
5771        while (NULL != pNext) {
5772            if (VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO == pNext->sType) {
5773                VkDeviceGroupDeviceCreateInfo *cur_struct = (VkDeviceGroupDeviceCreateInfo *)pNext;
5774                if (0 < cur_struct->physicalDeviceCount && NULL != cur_struct->pPhysicalDevices) {
5775                    VkDeviceGroupDeviceCreateInfo *temp_struct = loader_stack_alloc(sizeof(VkDeviceGroupDeviceCreateInfo));
5776                    VkPhysicalDevice *phys_dev_array = NULL;
5777                    if (NULL == temp_struct) {
5778                        return VK_ERROR_OUT_OF_HOST_MEMORY;
5779                    }
5780                    memcpy(temp_struct, cur_struct, sizeof(VkDeviceGroupDeviceCreateInfo));
5781                    phys_dev_array = loader_stack_alloc(sizeof(VkPhysicalDevice) * cur_struct->physicalDeviceCount);
5782                    if (NULL == phys_dev_array) {
5783                        return VK_ERROR_OUT_OF_HOST_MEMORY;
5784                    }
5785
5786                    // Before calling down, replace the incoming physical device values (which are really loader terminator
5787                    // physical devices) with the ICDs physical device values.
5788                    struct loader_physical_device_term *cur_term;
5789                    for (uint32_t phys_dev = 0; phys_dev < cur_struct->physicalDeviceCount; phys_dev++) {
5790                        cur_term = (struct loader_physical_device_term *)cur_struct->pPhysicalDevices[phys_dev];
5791                        phys_dev_array[phys_dev] = cur_term->phys_dev;
5792                    }
5793                    temp_struct->pPhysicalDevices = phys_dev_array;
5794
5795                    // Keep track of pointers to restore pNext chain before returning
5796                    caller_dgci_container = pPrev;
5797                    caller_dgci = cur_struct;
5798
5799                    // Replace the old struct in the pNext chain with this one.
5800                    pPrev->pNext = (VkBaseOutStructure *)temp_struct;
5801                }
5802                break;
5803            }
5804
5805            pPrev = pNext;
5806            pNext = pNext->pNext;
5807        }
5808    }
5809
5810    // Handle loader emulation for structs that are not supported by the ICD:
5811    // Presently, the emulation leaves the pNext chain alone. This means that the ICD will receive items in the chain which
5812    // are not recognized by the ICD. If this causes the ICD to fail, then the items would have to be removed here. The current
5813    // implementation does not remove them because copying the pNext chain would be impossible if the loader does not recognize
5814    // the any of the struct types, as the loader would not know the size to allocate and copy.
5815    // if (icd_term->dispatch.GetPhysicalDeviceFeatures2 == NULL && icd_term->dispatch.GetPhysicalDeviceFeatures2KHR == NULL) {
5816    {
5817        const void *pNext = localCreateInfo.pNext;
5818        while (pNext != NULL) {
5819            switch (*(VkStructureType *)pNext) {
5820                case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2: {
5821                    const VkPhysicalDeviceFeatures2KHR *features = pNext;
5822
5823                    if (icd_term->dispatch.GetPhysicalDeviceFeatures2 == NULL &&
5824                        icd_term->dispatch.GetPhysicalDeviceFeatures2KHR == NULL) {
5825                        loader_log(icd_term->this_instance, VULKAN_LOADER_INFO_BIT, 0,
5826                                   "vkCreateDevice: Emulating handling of VkPhysicalDeviceFeatures2 in pNext chain for ICD \"%s\"",
5827                                   icd_term->scanned_icd->lib_name);
5828
5829                        // Verify that VK_KHR_get_physical_device_properties2 is enabled
5830                        if (icd_term->this_instance->enabled_known_extensions.khr_get_physical_device_properties2) {
5831                            localCreateInfo.pEnabledFeatures = &features->features;
5832                        }
5833                    }
5834
5835                    // Leave this item in the pNext chain for now
5836
5837                    pNext = features->pNext;
5838                    break;
5839                }
5840
5841                case VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO: {
5842                    const VkDeviceGroupDeviceCreateInfo *group_info = pNext;
5843
5844                    if (icd_term->dispatch.EnumeratePhysicalDeviceGroups == NULL &&
5845                        icd_term->dispatch.EnumeratePhysicalDeviceGroupsKHR == NULL) {
5846                        loader_log(icd_term->this_instance, VULKAN_LOADER_INFO_BIT, 0,
5847                                   "vkCreateDevice: Emulating handling of VkPhysicalDeviceGroupProperties in pNext chain for "
5848                                   "ICD \"%s\"",
5849                                   icd_term->scanned_icd->lib_name);
5850
5851                        // The group must contain only this one device, since physical device groups aren't actually supported
5852                        if (group_info->physicalDeviceCount != 1) {
5853                            loader_log(icd_term->this_instance, VULKAN_LOADER_ERROR_BIT, 0,
5854                                       "vkCreateDevice: Emulation failed to create device from device group info");
5855                            res = VK_ERROR_INITIALIZATION_FAILED;
5856                            goto out;
5857                        }
5858                    }
5859
5860                    // Nothing needs to be done here because we're leaving the item in the pNext chain and because the spec
5861                    // states that the physicalDevice argument must be included in the device group, and we've already checked
5862                    // that it is
5863
5864                    pNext = group_info->pNext;
5865                    break;
5866                }
5867
5868                // Multiview properties are also allowed, but since VK_KHX_multiview is a device extension, we'll just let the
5869                // ICD handle that error when the user enables the extension here
5870                default: {
5871                    const VkBaseInStructure *header = pNext;
5872                    pNext = header->pNext;
5873                    break;
5874                }
5875            }
5876        }
5877    }
5878
5879    VkBool32 maintenance5_feature_enabled = false;
5880    // Look for the VkPhysicalDeviceMaintenance5FeaturesKHR struct to see if the feature was enabled
5881    {
5882        const void *pNext = localCreateInfo.pNext;
5883        while (pNext != NULL) {
5884            switch (*(VkStructureType *)pNext) {
5885                case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_FEATURES_KHR: {
5886                    const VkPhysicalDeviceMaintenance5FeaturesKHR *maintenance_features = pNext;
5887                    if (maintenance_features->maintenance5 == VK_TRUE) {
5888                        maintenance5_feature_enabled = true;
5889                    }
5890                    pNext = maintenance_features->pNext;
5891                    break;
5892                }
5893
5894                default: {
5895                    const VkBaseInStructure *header = pNext;
5896                    pNext = header->pNext;
5897                    break;
5898                }
5899            }
5900        }
5901    }
5902
5903    // Every extension that has a loader-defined terminator needs to be marked as enabled or disabled so that we know whether or
5904    // not to return that terminator when vkGetDeviceProcAddr is called
5905    for (uint32_t i = 0; i < localCreateInfo.enabledExtensionCount; ++i) {
5906        if (!strcmp(localCreateInfo.ppEnabledExtensionNames[i], VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
5907            dev->driver_extensions.khr_swapchain_enabled = true;
5908        } else if (!strcmp(localCreateInfo.ppEnabledExtensionNames[i], VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME)) {
5909            dev->driver_extensions.khr_display_swapchain_enabled = true;
5910        } else if (!strcmp(localCreateInfo.ppEnabledExtensionNames[i], VK_KHR_DEVICE_GROUP_EXTENSION_NAME)) {
5911            dev->driver_extensions.khr_device_group_enabled = true;
5912        } else if (!strcmp(localCreateInfo.ppEnabledExtensionNames[i], VK_EXT_DEBUG_MARKER_EXTENSION_NAME)) {
5913            dev->driver_extensions.ext_debug_marker_enabled = true;
5914        } else if (!strcmp(localCreateInfo.ppEnabledExtensionNames[i], "VK_EXT_full_screen_exclusive")) {
5915            dev->driver_extensions.ext_full_screen_exclusive_enabled = true;
5916        } else if (!strcmp(localCreateInfo.ppEnabledExtensionNames[i], VK_KHR_MAINTENANCE_5_EXTENSION_NAME) &&
5917                   maintenance5_feature_enabled) {
5918            dev->should_ignore_device_commands_from_newer_version = true;
5919        }
5920    }
5921    dev->layer_extensions.ext_debug_utils_enabled = icd_term->this_instance->enabled_known_extensions.ext_debug_utils;
5922    dev->driver_extensions.ext_debug_utils_enabled = icd_term->this_instance->enabled_known_extensions.ext_debug_utils;
5923
5924    VkPhysicalDeviceProperties properties;
5925    icd_term->dispatch.GetPhysicalDeviceProperties(phys_dev_term->phys_dev, &properties);
5926    if (!dev->driver_extensions.khr_device_group_enabled) {
5927        if (properties.apiVersion >= VK_API_VERSION_1_1) {
5928            dev->driver_extensions.khr_device_group_enabled = true;
5929        }
5930    }
5931
5932    loader_log(icd_term->this_instance, VULKAN_LOADER_LAYER_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
5933               "       Using \"%s\" with driver: \"%s\"", properties.deviceName, icd_term->scanned_icd->lib_name);
5934
5935    res = fpCreateDevice(phys_dev_term->phys_dev, &localCreateInfo, pAllocator, &dev->icd_device);
5936    if (res != VK_SUCCESS) {
5937        loader_log(icd_term->this_instance, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
5938                   "terminator_CreateDevice: Failed in ICD %s vkCreateDevice call", icd_term->scanned_icd->lib_name);
5939        goto out;
5940    }
5941
5942    *pDevice = dev->icd_device;
5943    loader_add_logical_device(icd_term, dev);
5944
5945    // Init dispatch pointer in new device object
5946    loader_init_dispatch(*pDevice, &dev->loader_dispatch);
5947
5948out:
5949    if (NULL != icd_exts.list) {
5950        loader_destroy_generic_list(icd_term->this_instance, (struct loader_generic_list *)&icd_exts);
5951    }
5952
5953    // Restore pNext pointer to old VkDeviceGroupDeviceCreateInfo
5954    // in the chain to maintain consistency for the caller.
5955    if (caller_dgci_container != NULL) {
5956        caller_dgci_container->pNext = (VkBaseOutStructure *)caller_dgci;
5957    }
5958
5959    return res;
5960}
5961
5962// Update the trampoline physical devices with the wrapped version.
5963// We always want to re-use previous physical device pointers since they may be used by an application
5964// after returning previously.
5965VkResult setup_loader_tramp_phys_devs(struct loader_instance *inst, uint32_t phys_dev_count, VkPhysicalDevice *phys_devs) {
5966    VkResult res = VK_SUCCESS;
5967    uint32_t found_count = 0;
5968    uint32_t old_count = inst->phys_dev_count_tramp;
5969    uint32_t new_count = inst->total_gpu_count;
5970    struct loader_physical_device_tramp **new_phys_devs = NULL;
5971
5972    if (0 == phys_dev_count) {
5973        return VK_SUCCESS;
5974    }
5975    if (phys_dev_count > new_count) {
5976        new_count = phys_dev_count;
5977    }
5978
5979    // We want an old to new index array and a new to old index array
5980    int32_t *old_to_new_index = (int32_t *)loader_stack_alloc(sizeof(int32_t) * old_count);
5981    int32_t *new_to_old_index = (int32_t *)loader_stack_alloc(sizeof(int32_t) * new_count);
5982    if (NULL == old_to_new_index || NULL == new_to_old_index) {
5983        return VK_ERROR_OUT_OF_HOST_MEMORY;
5984    }
5985
5986    // Initialize both
5987    for (uint32_t cur_idx = 0; cur_idx < old_count; ++cur_idx) {
5988        old_to_new_index[cur_idx] = -1;
5989    }
5990    for (uint32_t cur_idx = 0; cur_idx < new_count; ++cur_idx) {
5991        new_to_old_index[cur_idx] = -1;
5992    }
5993
5994    // Figure out the old->new and new->old indices
5995    for (uint32_t cur_idx = 0; cur_idx < old_count; ++cur_idx) {
5996        for (uint32_t new_idx = 0; new_idx < phys_dev_count; ++new_idx) {
5997            if (inst->phys_devs_tramp[cur_idx]->phys_dev == phys_devs[new_idx]) {
5998                old_to_new_index[cur_idx] = (int32_t)new_idx;
5999                new_to_old_index[new_idx] = (int32_t)cur_idx;
6000                found_count++;
6001                break;
6002            }
6003        }
6004    }
6005
6006    // If we found exactly the number of items we were looking for as we had before.  Then everything
6007    // we already have is good enough and we just need to update the array that was passed in with
6008    // the loader values.
6009    if (found_count == phys_dev_count && 0 != old_count && old_count == new_count) {
6010        for (uint32_t new_idx = 0; new_idx < phys_dev_count; ++new_idx) {
6011            for (uint32_t cur_idx = 0; cur_idx < old_count; ++cur_idx) {
6012                if (old_to_new_index[cur_idx] == (int32_t)new_idx) {
6013                    phys_devs[new_idx] = (VkPhysicalDevice)inst->phys_devs_tramp[cur_idx];
6014                    break;
6015                }
6016            }
6017        }
6018        // Nothing else to do for this path
6019        res = VK_SUCCESS;
6020    } else {
6021        // Something is different, so do the full path of checking every device and creating a new array to use.
6022        // This can happen if a device was added, or removed, or we hadn't previously queried all the data and we
6023        // have more to store.
6024        new_phys_devs = loader_instance_heap_calloc(inst, sizeof(struct loader_physical_device_tramp *) * new_count,
6025                                                    VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
6026        if (NULL == new_phys_devs) {
6027            loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
6028                       "setup_loader_tramp_phys_devs:  Failed to allocate new physical device array of size %d", new_count);
6029            res = VK_ERROR_OUT_OF_HOST_MEMORY;
6030            goto out;
6031        }
6032
6033        if (new_count > phys_dev_count) {
6034            found_count = phys_dev_count;
6035        } else {
6036            found_count = new_count;
6037        }
6038
6039        // First try to see if an old item exists that matches the new item.  If so, just copy it over.
6040        for (uint32_t new_idx = 0; new_idx < found_count; ++new_idx) {
6041            bool old_item_found = false;
6042            for (uint32_t cur_idx = 0; cur_idx < old_count; ++cur_idx) {
6043                if (old_to_new_index[cur_idx] == (int32_t)new_idx) {
6044                    // Copy over old item to correct spot in the new array
6045                    new_phys_devs[new_idx] = inst->phys_devs_tramp[cur_idx];
6046                    old_item_found = true;
6047                    break;
6048                }
6049            }
6050            // Something wasn't found, so it's new so add it to the new list
6051            if (!old_item_found) {
6052                new_phys_devs[new_idx] = loader_instance_heap_alloc(inst, sizeof(struct loader_physical_device_tramp),
6053                                                                    VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
6054                if (NULL == new_phys_devs[new_idx]) {
6055                    loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
6056                               "setup_loader_tramp_phys_devs:  Failed to allocate new trampoline physical device");
6057                    res = VK_ERROR_OUT_OF_HOST_MEMORY;
6058                    goto out;
6059                }
6060
6061                // Initialize the new physicalDevice object
6062                loader_set_dispatch((void *)new_phys_devs[new_idx], inst->disp);
6063                new_phys_devs[new_idx]->this_instance = inst;
6064                new_phys_devs[new_idx]->phys_dev = phys_devs[new_idx];
6065                new_phys_devs[new_idx]->magic = PHYS_TRAMP_MAGIC_NUMBER;
6066            }
6067
6068            phys_devs[new_idx] = (VkPhysicalDevice)new_phys_devs[new_idx];
6069        }
6070
6071        // We usually get here if the user array is smaller than the total number of devices, so copy the
6072        // remaining devices we have over to the new array.
6073        uint32_t start = found_count;
6074        for (uint32_t new_idx = start; new_idx < new_count; ++new_idx) {
6075            for (uint32_t cur_idx = 0; cur_idx < old_count; ++cur_idx) {
6076                if (old_to_new_index[cur_idx] == -1) {
6077                    new_phys_devs[new_idx] = inst->phys_devs_tramp[cur_idx];
6078                    old_to_new_index[cur_idx] = new_idx;
6079                    found_count++;
6080                    break;
6081                }
6082            }
6083        }
6084    }
6085
6086out:
6087
6088    if (NULL != new_phys_devs) {
6089        if (VK_SUCCESS != res) {
6090            for (uint32_t new_idx = 0; new_idx < found_count; ++new_idx) {
6091                // If an OOM occurred inside the copying of the new physical devices into the existing array
6092                // will leave some of the old physical devices in the array which may have been copied into
6093                // the new array, leading to them being freed twice. To avoid this we just make sure to not
6094                // delete physical devices which were copied.
6095                bool found = false;
6096                for (uint32_t cur_idx = 0; cur_idx < inst->phys_dev_count_tramp; cur_idx++) {
6097                    if (new_phys_devs[new_idx] == inst->phys_devs_tramp[cur_idx]) {
6098                        found = true;
6099                        break;
6100                    }
6101                }
6102                if (!found) {
6103                    loader_instance_heap_free(inst, new_phys_devs[new_idx]);
6104                }
6105            }
6106            loader_instance_heap_free(inst, new_phys_devs);
6107        } else {
6108            if (new_count > inst->total_gpu_count) {
6109                inst->total_gpu_count = new_count;
6110            }
6111            // Free everything in the old array that was not copied into the new array
6112            // here.  We can't attempt to do that before here since the previous loop
6113            // looking before the "out:" label may hit an out of memory condition resulting
6114            // in memory leaking.
6115            if (NULL != inst->phys_devs_tramp) {
6116                for (uint32_t i = 0; i < inst->phys_dev_count_tramp; i++) {
6117                    bool found = false;
6118                    for (uint32_t j = 0; j < inst->total_gpu_count; j++) {
6119                        if (inst->phys_devs_tramp[i] == new_phys_devs[j]) {
6120                            found = true;
6121                            break;
6122                        }
6123                    }
6124                    if (!found) {
6125                        loader_instance_heap_free(inst, inst->phys_devs_tramp[i]);
6126                    }
6127                }
6128                loader_instance_heap_free(inst, inst->phys_devs_tramp);
6129            }
6130            inst->phys_devs_tramp = new_phys_devs;
6131            inst->phys_dev_count_tramp = found_count;
6132        }
6133    }
6134    if (VK_SUCCESS != res) {
6135        inst->total_gpu_count = 0;
6136    }
6137
6138    return res;
6139}
6140
6141#if defined(LOADER_ENABLE_LINUX_SORT)
6142bool is_linux_sort_enabled(struct loader_instance *inst) {
6143    bool sort_items = inst->supports_get_dev_prop_2;
6144    char *env_value = loader_getenv("VK_LOADER_DISABLE_SELECT", inst);
6145    if (NULL != env_value) {
6146        int32_t int_env_val = atoi(env_value);
6147        loader_free_getenv(env_value, inst);
6148        if (int_env_val != 0) {
6149            sort_items = false;
6150        }
6151    }
6152    return sort_items;
6153}
6154#endif  // LOADER_ENABLE_LINUX_SORT
6155
6156// Look for physical_device in the provided phys_devs list, return true if found and put the index into out_idx, otherwise
6157// return false
6158bool find_phys_dev(VkPhysicalDevice physical_device, uint32_t phys_devs_count, struct loader_physical_device_term **phys_devs,
6159                   uint32_t *out_idx) {
6160    if (NULL == phys_devs) return false;
6161    for (uint32_t idx = 0; idx < phys_devs_count; idx++) {
6162        if (NULL != phys_devs[idx] && physical_device == phys_devs[idx]->phys_dev) {
6163            *out_idx = idx;
6164            return true;
6165        }
6166    }
6167    return false;
6168}
6169
6170// Add physical_device to new_phys_devs
6171VkResult check_and_add_to_new_phys_devs(struct loader_instance *inst, VkPhysicalDevice physical_device,
6172                                        struct loader_icd_physical_devices *dev_array, uint32_t *cur_new_phys_dev_count,
6173                                        struct loader_physical_device_term **new_phys_devs) {
6174    uint32_t out_idx = 0;
6175    uint32_t idx = *cur_new_phys_dev_count;
6176    // Check if the physical_device already exists in the new_phys_devs buffer, that means it was found from both
6177    // EnumerateAdapterPhysicalDevices and EnumeratePhysicalDevices and we need to skip it.
6178    if (find_phys_dev(physical_device, idx, new_phys_devs, &out_idx)) {
6179        return VK_SUCCESS;
6180    }
6181    // Check if it was found in a previous call to vkEnumeratePhysicalDevices, we can just copy over the old data.
6182    if (find_phys_dev(physical_device, inst->phys_dev_count_term, inst->phys_devs_term, &out_idx)) {
6183        new_phys_devs[idx] = inst->phys_devs_term[out_idx];
6184        (*cur_new_phys_dev_count)++;
6185        return VK_SUCCESS;
6186    }
6187
6188    // Exit in case something is already present - this shouldn't happen but better to be safe than overwrite existing data
6189    // since this code has been refactored a half dozen times.
6190    if (NULL != new_phys_devs[idx]) {
6191        return VK_SUCCESS;
6192    }
6193    // If this physical device is new, we need to allocate space for it.
6194    new_phys_devs[idx] =
6195        loader_instance_heap_alloc(inst, sizeof(struct loader_physical_device_term), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
6196    if (NULL == new_phys_devs[idx]) {
6197        loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
6198                   "check_and_add_to_new_phys_devs:  Failed to allocate physical device terminator object %d", idx);
6199        return VK_ERROR_OUT_OF_HOST_MEMORY;
6200    }
6201
6202    loader_set_dispatch((void *)new_phys_devs[idx], inst->disp);
6203    new_phys_devs[idx]->this_icd_term = dev_array->icd_term;
6204    new_phys_devs[idx]->icd_index = (uint8_t)(dev_array->icd_index);
6205    new_phys_devs[idx]->phys_dev = physical_device;
6206
6207    // Increment the count of new physical devices
6208    (*cur_new_phys_dev_count)++;
6209    return VK_SUCCESS;
6210}
6211
6212/* Enumerate all physical devices from ICDs and add them to inst->phys_devs_term
6213 *
6214 * There are two methods to find VkPhysicalDevices - vkEnumeratePhysicalDevices and vkEnumerateAdapterPhysicalDevices
6215 * The latter is supported on windows only and on devices supporting ICD Interface Version 6 and greater.
6216 *
6217 * Once all physical devices are acquired, they need to be pulled into a single list of `loader_physical_device_term`'s.
6218 * They also need to be setup - the icd_term, icd_index, phys_dev, and disp (dispatch table) all need the correct data.
6219 * Additionally, we need to keep using already setup physical devices as they may be in use, thus anything enumerated
6220 * that is already in inst->phys_devs_term will be carried over.
6221 */
6222
6223VkResult setup_loader_term_phys_devs(struct loader_instance *inst) {
6224    VkResult res = VK_SUCCESS;
6225    struct loader_icd_term *icd_term;
6226    uint32_t icd_idx = 0;
6227    uint32_t windows_sorted_devices_count = 0;
6228    struct loader_icd_physical_devices *windows_sorted_devices_array = NULL;
6229    uint32_t icd_count = 0;
6230    struct loader_icd_physical_devices *icd_phys_dev_array = NULL;
6231    uint32_t new_phys_devs_capacity = 0;
6232    uint32_t new_phys_devs_count = 0;
6233    struct loader_physical_device_term **new_phys_devs = NULL;
6234
6235#if defined(_WIN32)
6236    // Get the physical devices supported by platform sorting mechanism into a separate list
6237    res = windows_read_sorted_physical_devices(inst, &windows_sorted_devices_count, &windows_sorted_devices_array);
6238    if (VK_SUCCESS != res) {
6239        goto out;
6240    }
6241#endif
6242
6243    icd_count = inst->total_icd_count;
6244
6245    // Allocate something to store the physical device characteristics that we read from each ICD.
6246    icd_phys_dev_array =
6247        (struct loader_icd_physical_devices *)loader_stack_alloc(sizeof(struct loader_icd_physical_devices) * icd_count);
6248    if (NULL == icd_phys_dev_array) {
6249        loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
6250                   "setup_loader_term_phys_devs:  Failed to allocate temporary ICD Physical device info array of size %d",
6251                   icd_count);
6252        res = VK_ERROR_OUT_OF_HOST_MEMORY;
6253        goto out;
6254    }
6255    memset(icd_phys_dev_array, 0, sizeof(struct loader_icd_physical_devices) * icd_count);
6256
6257    // For each ICD, query the number of physical devices, and then get an
6258    // internal value for those physical devices.
6259    icd_term = inst->icd_terms;
6260    while (NULL != icd_term) {
6261        res = icd_term->dispatch.EnumeratePhysicalDevices(icd_term->instance, &icd_phys_dev_array[icd_idx].device_count, NULL);
6262        if (VK_SUCCESS != res) {
6263            loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
6264                       "setup_loader_term_phys_devs:  Call to ICD %d's \'vkEnumeratePhysicalDevices\' failed with error 0x%08x",
6265                       icd_idx, res);
6266            goto out;
6267        }
6268
6269        icd_phys_dev_array[icd_idx].physical_devices =
6270            (VkPhysicalDevice *)loader_stack_alloc(icd_phys_dev_array[icd_idx].device_count * sizeof(VkPhysicalDevice));
6271        if (NULL == icd_phys_dev_array[icd_idx].physical_devices) {
6272            loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
6273                       "setup_loader_term_phys_devs:  Failed to allocate temporary ICD Physical device array for ICD %d of size %d",
6274                       icd_idx, icd_phys_dev_array[icd_idx].device_count);
6275            res = VK_ERROR_OUT_OF_HOST_MEMORY;
6276            goto out;
6277        }
6278
6279        res = icd_term->dispatch.EnumeratePhysicalDevices(icd_term->instance, &(icd_phys_dev_array[icd_idx].device_count),
6280                                                          icd_phys_dev_array[icd_idx].physical_devices);
6281        if (VK_SUCCESS != res) {
6282            goto out;
6283        }
6284        icd_phys_dev_array[icd_idx].icd_term = icd_term;
6285        icd_phys_dev_array[icd_idx].icd_index = icd_idx;
6286        icd_term = icd_term->next;
6287        ++icd_idx;
6288    }
6289
6290    // Add up both the windows sorted and non windows found physical device counts
6291    for (uint32_t i = 0; i < windows_sorted_devices_count; ++i) {
6292        new_phys_devs_capacity += windows_sorted_devices_array[i].device_count;
6293    }
6294    for (uint32_t i = 0; i < icd_count; ++i) {
6295        new_phys_devs_capacity += icd_phys_dev_array[i].device_count;
6296    }
6297
6298    // Bail out if there are no physical devices reported
6299    if (0 == new_phys_devs_capacity) {
6300        loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
6301                   "setup_loader_term_phys_devs:  Failed to detect any valid GPUs in the current config");
6302        res = VK_ERROR_INITIALIZATION_FAILED;
6303        goto out;
6304    }
6305
6306    // Create an allocation large enough to hold both the windows sorting enumeration and non-windows physical device
6307    // enumeration
6308    new_phys_devs = loader_instance_heap_calloc(inst, sizeof(struct loader_physical_device_term *) * new_phys_devs_capacity,
6309                                                VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
6310    if (NULL == new_phys_devs) {
6311        loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
6312                   "setup_loader_term_phys_devs:  Failed to allocate new physical device array of size %d", new_phys_devs_capacity);
6313        res = VK_ERROR_OUT_OF_HOST_MEMORY;
6314        goto out;
6315    }
6316
6317    // Copy over everything found through sorted enumeration
6318    for (uint32_t i = 0; i < windows_sorted_devices_count; ++i) {
6319        for (uint32_t j = 0; j < windows_sorted_devices_array[i].device_count; ++j) {
6320            res = check_and_add_to_new_phys_devs(inst, windows_sorted_devices_array[i].physical_devices[j],
6321                                                 &windows_sorted_devices_array[i], &new_phys_devs_count, new_phys_devs);
6322            if (res == VK_ERROR_OUT_OF_HOST_MEMORY) {
6323                goto out;
6324            }
6325        }
6326    }
6327
6328// Now go through the rest of the physical devices and add them to new_phys_devs
6329#if defined(LOADER_ENABLE_LINUX_SORT)
6330
6331    if (is_linux_sort_enabled(inst)) {
6332        for (uint32_t dev = new_phys_devs_count; dev < new_phys_devs_capacity; ++dev) {
6333            new_phys_devs[dev] =
6334                loader_instance_heap_alloc(inst, sizeof(struct loader_physical_device_term), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
6335            if (NULL == new_phys_devs[dev]) {
6336                loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
6337                           "setup_loader_term_phys_devs:  Failed to allocate physical device terminator object %d", dev);
6338                res = VK_ERROR_OUT_OF_HOST_MEMORY;
6339                goto out;
6340            }
6341        }
6342
6343        // Get the physical devices supported by platform sorting mechanism into a separate list
6344        // Pass in a sublist to the function so it only operates on the correct elements. This means passing in a pointer to the
6345        // current next element in new_phys_devs and passing in a `count` of currently unwritten elements
6346        res = linux_read_sorted_physical_devices(inst, icd_count, icd_phys_dev_array, new_phys_devs_capacity - new_phys_devs_count,
6347                                                 &new_phys_devs[new_phys_devs_count]);
6348        if (res == VK_ERROR_OUT_OF_HOST_MEMORY) {
6349            goto out;
6350        }
6351        // Keep previously allocated physical device info since apps may already be using that!
6352        for (uint32_t new_idx = new_phys_devs_count; new_idx < new_phys_devs_capacity; new_idx++) {
6353            for (uint32_t old_idx = 0; old_idx < inst->phys_dev_count_term; old_idx++) {
6354                if (new_phys_devs[new_idx]->phys_dev == inst->phys_devs_term[old_idx]->phys_dev) {
6355                    loader_log(inst, VULKAN_LOADER_DEBUG_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
6356                               "Copying old device %u into new device %u", old_idx, new_idx);
6357                    // Free the old new_phys_devs info since we're not using it before we assign the new info
6358                    loader_instance_heap_free(inst, new_phys_devs[new_idx]);
6359                    new_phys_devs[new_idx] = inst->phys_devs_term[old_idx];
6360                    break;
6361                }
6362            }
6363        }
6364        // now set the count to the capacity, as now the list is filled in
6365        new_phys_devs_count = new_phys_devs_capacity;
6366        // We want the following code to run if either linux sorting is disabled at compile time or runtime
6367    } else {
6368#endif  // LOADER_ENABLE_LINUX_SORT
6369
6370        // Copy over everything found through the non-sorted means.
6371        for (uint32_t i = 0; i < icd_count; ++i) {
6372            for (uint32_t j = 0; j < icd_phys_dev_array[i].device_count; ++j) {
6373                res = check_and_add_to_new_phys_devs(inst, icd_phys_dev_array[i].physical_devices[j], &icd_phys_dev_array[i],
6374                                                     &new_phys_devs_count, new_phys_devs);
6375                if (res == VK_ERROR_OUT_OF_HOST_MEMORY) {
6376                    goto out;
6377                }
6378            }
6379        }
6380#if defined(LOADER_ENABLE_LINUX_SORT)
6381    }
6382#endif  // LOADER_ENABLE_LINUX_SORT
6383out:
6384
6385    if (VK_SUCCESS != res) {
6386        if (NULL != new_phys_devs) {
6387            // We've encountered an error, so we should free the new buffers.
6388            for (uint32_t i = 0; i < new_phys_devs_capacity; i++) {
6389                // May not have allocated this far, skip it if we hadn't.
6390                if (new_phys_devs[i] == NULL) continue;
6391
6392                // If an OOM occurred inside the copying of the new physical devices into the existing array
6393                // will leave some of the old physical devices in the array which may have been copied into
6394                // the new array, leading to them being freed twice. To avoid this we just make sure to not
6395                // delete physical devices which were copied.
6396                bool found = false;
6397                if (NULL != inst->phys_devs_term) {
6398                    for (uint32_t old_idx = 0; old_idx < inst->phys_dev_count_term; old_idx++) {
6399                        if (new_phys_devs[i] == inst->phys_devs_term[old_idx]) {
6400                            found = true;
6401                            break;
6402                        }
6403                    }
6404                }
6405                if (!found) {
6406                    loader_instance_heap_free(inst, new_phys_devs[i]);
6407                }
6408            }
6409            loader_instance_heap_free(inst, new_phys_devs);
6410        }
6411        inst->total_gpu_count = 0;
6412    } else {
6413        if (NULL != inst->phys_devs_term) {
6414            // Free everything in the old array that was not copied into the new array
6415            // here.  We can't attempt to do that before here since the previous loop
6416            // looking before the "out:" label may hit an out of memory condition resulting
6417            // in memory leaking.
6418            for (uint32_t i = 0; i < inst->phys_dev_count_term; i++) {
6419                bool found = false;
6420                for (uint32_t j = 0; j < new_phys_devs_count; j++) {
6421                    if (new_phys_devs != NULL && inst->phys_devs_term[i] == new_phys_devs[j]) {
6422                        found = true;
6423                        break;
6424                    }
6425                }
6426                if (!found) {
6427                    loader_instance_heap_free(inst, inst->phys_devs_term[i]);
6428                }
6429            }
6430            loader_instance_heap_free(inst, inst->phys_devs_term);
6431        }
6432
6433        // Swap out old and new devices list
6434        inst->phys_dev_count_term = new_phys_devs_count;
6435        inst->phys_devs_term = new_phys_devs;
6436        inst->total_gpu_count = new_phys_devs_count;
6437    }
6438
6439    if (windows_sorted_devices_array != NULL) {
6440        for (uint32_t i = 0; i < windows_sorted_devices_count; ++i) {
6441            if (windows_sorted_devices_array[i].device_count > 0 && windows_sorted_devices_array[i].physical_devices != NULL) {
6442                loader_instance_heap_free(inst, windows_sorted_devices_array[i].physical_devices);
6443            }
6444        }
6445        loader_instance_heap_free(inst, windows_sorted_devices_array);
6446    }
6447
6448    return res;
6449}
6450
6451VkResult setup_loader_tramp_phys_dev_groups(struct loader_instance *inst, uint32_t group_count,
6452                                            VkPhysicalDeviceGroupProperties *groups) {
6453    VkResult res = VK_SUCCESS;
6454    uint32_t cur_idx;
6455    uint32_t dev_idx;
6456
6457    if (0 == group_count) {
6458        return VK_SUCCESS;
6459    }
6460
6461    // Generate a list of all the devices and convert them to the loader ID
6462    uint32_t phys_dev_count = 0;
6463    for (cur_idx = 0; cur_idx < group_count; ++cur_idx) {
6464        phys_dev_count += groups[cur_idx].physicalDeviceCount;
6465    }
6466    VkPhysicalDevice *devices = (VkPhysicalDevice *)loader_stack_alloc(sizeof(VkPhysicalDevice) * phys_dev_count);
6467    if (NULL == devices) {
6468        return VK_ERROR_OUT_OF_HOST_MEMORY;
6469    }
6470
6471    uint32_t cur_device = 0;
6472    for (cur_idx = 0; cur_idx < group_count; ++cur_idx) {
6473        for (dev_idx = 0; dev_idx < groups[cur_idx].physicalDeviceCount; ++dev_idx) {
6474            devices[cur_device++] = groups[cur_idx].physicalDevices[dev_idx];
6475        }
6476    }
6477
6478    // Update the devices based on the loader physical device values.
6479    res = setup_loader_tramp_phys_devs(inst, phys_dev_count, devices);
6480    if (VK_SUCCESS != res) {
6481        return res;
6482    }
6483
6484    // Update the devices in the group structures now
6485    cur_device = 0;
6486    for (cur_idx = 0; cur_idx < group_count; ++cur_idx) {
6487        for (dev_idx = 0; dev_idx < groups[cur_idx].physicalDeviceCount; ++dev_idx) {
6488            groups[cur_idx].physicalDevices[dev_idx] = devices[cur_device++];
6489        }
6490    }
6491
6492    return res;
6493}
6494
6495VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount,
6496                                                                   VkPhysicalDevice *pPhysicalDevices) {
6497    struct loader_instance *inst = (struct loader_instance *)instance;
6498    VkResult res = VK_SUCCESS;
6499
6500    // Always call the setup loader terminator physical devices because they may
6501    // have changed at any point.
6502    res = setup_loader_term_phys_devs(inst);
6503    if (VK_SUCCESS != res) {
6504        goto out;
6505    }
6506
6507    uint32_t copy_count = inst->phys_dev_count_term;
6508    if (NULL != pPhysicalDevices) {
6509        if (copy_count > *pPhysicalDeviceCount) {
6510            copy_count = *pPhysicalDeviceCount;
6511            loader_log(inst, VULKAN_LOADER_INFO_BIT, 0,
6512                       "terminator_EnumeratePhysicalDevices : Trimming device count from %d to %d.", inst->phys_dev_count_term,
6513                       copy_count);
6514            res = VK_INCOMPLETE;
6515        }
6516
6517        for (uint32_t i = 0; i < copy_count; i++) {
6518            pPhysicalDevices[i] = (VkPhysicalDevice)inst->phys_devs_term[i];
6519        }
6520    }
6521
6522    *pPhysicalDeviceCount = copy_count;
6523
6524out:
6525
6526    return res;
6527}
6528
6529VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
6530                                                                             const char *pLayerName, uint32_t *pPropertyCount,
6531                                                                             VkExtensionProperties *pProperties) {
6532    if (NULL == pPropertyCount) {
6533        return VK_INCOMPLETE;
6534    }
6535
6536    struct loader_physical_device_term *phys_dev_term;
6537
6538    // Any layer or trampoline wrapping should be removed at this point in time can just cast to the expected
6539    // type for VkPhysicalDevice.
6540    phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
6541
6542    // if we got here with a non-empty pLayerName, look up the extensions
6543    // from the json
6544    if (pLayerName != NULL && strlen(pLayerName) > 0) {
6545        uint32_t count;
6546        uint32_t copy_size;
6547        const struct loader_instance *inst = phys_dev_term->this_icd_term->this_instance;
6548        struct loader_device_extension_list *dev_ext_list = NULL;
6549        struct loader_device_extension_list local_ext_list;
6550        memset(&local_ext_list, 0, sizeof(local_ext_list));
6551        if (vk_string_validate(MaxLoaderStringLength, pLayerName) == VK_STRING_ERROR_NONE) {
6552            for (uint32_t i = 0; i < inst->instance_layer_list.count; i++) {
6553                struct loader_layer_properties *props = &inst->instance_layer_list.list[i];
6554                if (strcmp(props->info.layerName, pLayerName) == 0) {
6555                    dev_ext_list = &props->device_extension_list;
6556                }
6557            }
6558
6559            count = (dev_ext_list == NULL) ? 0 : dev_ext_list->count;
6560            if (pProperties == NULL) {
6561                *pPropertyCount = count;
6562                loader_destroy_generic_list(inst, (struct loader_generic_list *)&local_ext_list);
6563                return VK_SUCCESS;
6564            }
6565
6566            copy_size = *pPropertyCount < count ? *pPropertyCount : count;
6567            for (uint32_t i = 0; i < copy_size; i++) {
6568                memcpy(&pProperties[i], &dev_ext_list->list[i].props, sizeof(VkExtensionProperties));
6569            }
6570            *pPropertyCount = copy_size;
6571
6572            loader_destroy_generic_list(inst, (struct loader_generic_list *)&local_ext_list);
6573            if (copy_size < count) {
6574                return VK_INCOMPLETE;
6575            }
6576        } else {
6577            loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
6578                       "vkEnumerateDeviceExtensionProperties:  pLayerName is too long or is badly formed");
6579            return VK_ERROR_EXTENSION_NOT_PRESENT;
6580        }
6581
6582        return VK_SUCCESS;
6583    }
6584
6585    // user is querying driver extensions and has supplied their own storage - just fill it out
6586    else if (pProperties) {
6587        struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
6588        uint32_t written_count = *pPropertyCount;
6589        VkResult res =
6590            icd_term->dispatch.EnumerateDeviceExtensionProperties(phys_dev_term->phys_dev, NULL, &written_count, pProperties);
6591        if (res != VK_SUCCESS) {
6592            return res;
6593        }
6594
6595        // Iterate over active layers, if they are an implicit layer, add their device extensions
6596        // After calling into the driver, written_count contains the amount of device extensions written. We can therefore write
6597        // layer extensions starting at that point in pProperties
6598        for (uint32_t i = 0; i < icd_term->this_instance->expanded_activated_layer_list.count; i++) {
6599            struct loader_layer_properties *layer_props = icd_term->this_instance->expanded_activated_layer_list.list[i];
6600            if (0 == (layer_props->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER)) {
6601                struct loader_device_extension_list *layer_ext_list = &layer_props->device_extension_list;
6602                for (uint32_t j = 0; j < layer_ext_list->count; j++) {
6603                    struct loader_dev_ext_props *cur_ext_props = &layer_ext_list->list[j];
6604                    // look for duplicates
6605                    if (has_vk_extension_property_array(&cur_ext_props->props, written_count, pProperties)) {
6606                        continue;
6607                    }
6608
6609                    if (*pPropertyCount <= written_count) {
6610                        return VK_INCOMPLETE;
6611                    }
6612
6613                    memcpy(&pProperties[written_count], &cur_ext_props->props, sizeof(VkExtensionProperties));
6614                    written_count++;
6615                }
6616            }
6617        }
6618        // Make sure we update the pPropertyCount with the how many were written
6619        *pPropertyCount = written_count;
6620        return res;
6621    }
6622    // Use `goto out;` for rest of this function
6623
6624    // This case is during the call down the instance chain with pLayerName == NULL and pProperties == NULL
6625    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
6626    struct loader_extension_list all_exts = {0};
6627    VkResult res;
6628
6629    // We need to find the count without duplicates. This requires querying the driver for the names of the extensions.
6630    res = icd_term->dispatch.EnumerateDeviceExtensionProperties(phys_dev_term->phys_dev, NULL, &all_exts.count, NULL);
6631    if (res != VK_SUCCESS) {
6632        goto out;
6633    }
6634    // Then allocate memory to store the physical device extension list + the extensions layers provide
6635    // all_exts.count currently is the number of driver extensions
6636    all_exts.capacity = sizeof(VkExtensionProperties) * (all_exts.count + 20);
6637    all_exts.list = loader_instance_heap_alloc(icd_term->this_instance, all_exts.capacity, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
6638    if (NULL == all_exts.list) {
6639        res = VK_ERROR_OUT_OF_HOST_MEMORY;
6640        goto out;
6641    }
6642
6643    // Get the available device extensions and put them in all_exts.list
6644    res = icd_term->dispatch.EnumerateDeviceExtensionProperties(phys_dev_term->phys_dev, NULL, &all_exts.count, all_exts.list);
6645    if (res != VK_SUCCESS) {
6646        goto out;
6647    }
6648
6649    // Iterate over active layers, if they are an implicit layer, add their device extensions to all_exts.list
6650    for (uint32_t i = 0; i < icd_term->this_instance->expanded_activated_layer_list.count; i++) {
6651        struct loader_layer_properties *layer_props = icd_term->this_instance->expanded_activated_layer_list.list[i];
6652        if (0 == (layer_props->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER)) {
6653            struct loader_device_extension_list *layer_ext_list = &layer_props->device_extension_list;
6654            for (uint32_t j = 0; j < layer_ext_list->count; j++) {
6655                res = loader_add_to_ext_list(icd_term->this_instance, &all_exts, 1, &layer_ext_list->list[j].props);
6656                if (res != VK_SUCCESS) {
6657                    goto out;
6658                }
6659            }
6660        }
6661    }
6662
6663    // Write out the final de-duplicated count to pPropertyCount
6664    *pPropertyCount = all_exts.count;
6665    res = VK_SUCCESS;
6666
6667out:
6668
6669    loader_destroy_generic_list(icd_term->this_instance, (struct loader_generic_list *)&all_exts);
6670    return res;
6671}
6672
6673VkStringErrorFlags vk_string_validate(const int max_length, const char *utf8) {
6674    VkStringErrorFlags result = VK_STRING_ERROR_NONE;
6675    int num_char_bytes = 0;
6676    int i, j;
6677
6678    if (utf8 == NULL) {
6679        return VK_STRING_ERROR_NULL_PTR;
6680    }
6681
6682    for (i = 0; i <= max_length; i++) {
6683        if (utf8[i] == 0) {
6684            break;
6685        } else if (i == max_length) {
6686            result |= VK_STRING_ERROR_LENGTH;
6687            break;
6688        } else if ((utf8[i] >= 0x20) && (utf8[i] < 0x7f)) {
6689            num_char_bytes = 0;
6690        } else if ((utf8[i] & UTF8_ONE_BYTE_MASK) == UTF8_ONE_BYTE_CODE) {
6691            num_char_bytes = 1;
6692        } else if ((utf8[i] & UTF8_TWO_BYTE_MASK) == UTF8_TWO_BYTE_CODE) {
6693            num_char_bytes = 2;
6694        } else if ((utf8[i] & UTF8_THREE_BYTE_MASK) == UTF8_THREE_BYTE_CODE) {
6695            num_char_bytes = 3;
6696        } else {
6697            result = VK_STRING_ERROR_BAD_DATA;
6698        }
6699
6700        // Validate the following num_char_bytes of data
6701        for (j = 0; (j < num_char_bytes) && (i < max_length); j++) {
6702            if (++i == max_length) {
6703                result |= VK_STRING_ERROR_LENGTH;
6704                break;
6705            }
6706            if ((utf8[i] & UTF8_DATA_BYTE_MASK) != UTF8_DATA_BYTE_CODE) {
6707                result |= VK_STRING_ERROR_BAD_DATA;
6708            }
6709        }
6710    }
6711    return result;
6712}
6713
6714VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateInstanceVersion(const VkEnumerateInstanceVersionChain *chain,
6715                                                                   uint32_t *pApiVersion) {
6716    (void)chain;
6717    // NOTE: The Vulkan WG doesn't want us checking pApiVersion for NULL, but instead
6718    // prefers us crashing.
6719    *pApiVersion = VK_HEADER_VERSION_COMPLETE;
6720    return VK_SUCCESS;
6721}
6722
6723VKAPI_ATTR VkResult VKAPI_CALL
6724terminator_EnumerateInstanceExtensionProperties(const VkEnumerateInstanceExtensionPropertiesChain *chain, const char *pLayerName,
6725                                                uint32_t *pPropertyCount, VkExtensionProperties *pProperties) {
6726    (void)chain;
6727    struct loader_extension_list *global_ext_list = NULL;
6728    struct loader_layer_list instance_layers;
6729    struct loader_extension_list local_ext_list;
6730    struct loader_icd_tramp_list icd_tramp_list;
6731    uint32_t copy_size;
6732    VkResult res = VK_SUCCESS;
6733    struct loader_envvar_all_filters layer_filters = {0};
6734
6735    memset(&local_ext_list, 0, sizeof(local_ext_list));
6736    memset(&instance_layers, 0, sizeof(instance_layers));
6737    memset(&icd_tramp_list, 0, sizeof(icd_tramp_list));
6738
6739    res = parse_layer_environment_var_filters(NULL, &layer_filters);
6740    if (VK_SUCCESS != res) {
6741        goto out;
6742    }
6743
6744    // Get layer libraries if needed
6745    if (pLayerName && strlen(pLayerName) != 0) {
6746        if (vk_string_validate(MaxLoaderStringLength, pLayerName) != VK_STRING_ERROR_NONE) {
6747            assert(VK_FALSE && "vkEnumerateInstanceExtensionProperties: pLayerName is too long or is badly formed");
6748            res = VK_ERROR_EXTENSION_NOT_PRESENT;
6749            goto out;
6750        }
6751
6752        res = loader_scan_for_layers(NULL, &instance_layers, &layer_filters);
6753        if (VK_SUCCESS != res) {
6754            goto out;
6755        }
6756        for (uint32_t i = 0; i < instance_layers.count; i++) {
6757            struct loader_layer_properties *props = &instance_layers.list[i];
6758            if (strcmp(props->info.layerName, pLayerName) == 0) {
6759                global_ext_list = &props->instance_extension_list;
6760                break;
6761            }
6762        }
6763    } else {
6764        // Preload ICD libraries so subsequent calls to EnumerateInstanceExtensionProperties don't have to load them
6765        loader_preload_icds();
6766
6767        // Scan/discover all ICD libraries
6768        res = loader_icd_scan(NULL, &icd_tramp_list, NULL, NULL);
6769        // EnumerateInstanceExtensionProperties can't return anything other than OOM or VK_ERROR_LAYER_NOT_PRESENT
6770        if ((VK_SUCCESS != res && icd_tramp_list.count > 0) || res == VK_ERROR_OUT_OF_HOST_MEMORY) {
6771            goto out;
6772        }
6773        // Get extensions from all ICD's, merge so no duplicates
6774        res = loader_get_icd_loader_instance_extensions(NULL, &icd_tramp_list, &local_ext_list);
6775        if (VK_SUCCESS != res) {
6776            goto out;
6777        }
6778        loader_scanned_icd_clear(NULL, &icd_tramp_list);
6779
6780        // Append enabled implicit layers.
6781        res = loader_scan_for_implicit_layers(NULL, &instance_layers, &layer_filters);
6782        if (VK_SUCCESS != res) {
6783            goto out;
6784        }
6785        for (uint32_t i = 0; i < instance_layers.count; i++) {
6786            struct loader_extension_list *ext_list = &instance_layers.list[i].instance_extension_list;
6787            loader_add_to_ext_list(NULL, &local_ext_list, ext_list->count, ext_list->list);
6788        }
6789
6790        global_ext_list = &local_ext_list;
6791    }
6792
6793    if (global_ext_list == NULL) {
6794        res = VK_ERROR_LAYER_NOT_PRESENT;
6795        goto out;
6796    }
6797
6798    if (pProperties == NULL) {
6799        *pPropertyCount = global_ext_list->count;
6800        goto out;
6801    }
6802
6803    copy_size = *pPropertyCount < global_ext_list->count ? *pPropertyCount : global_ext_list->count;
6804    for (uint32_t i = 0; i < copy_size; i++) {
6805        memcpy(&pProperties[i], &global_ext_list->list[i], sizeof(VkExtensionProperties));
6806    }
6807    *pPropertyCount = copy_size;
6808
6809    if (copy_size < global_ext_list->count) {
6810        res = VK_INCOMPLETE;
6811        goto out;
6812    }
6813
6814out:
6815    loader_destroy_generic_list(NULL, (struct loader_generic_list *)&icd_tramp_list);
6816    loader_destroy_generic_list(NULL, (struct loader_generic_list *)&local_ext_list);
6817    loader_delete_layer_list_and_properties(NULL, &instance_layers);
6818    return res;
6819}
6820
6821VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateInstanceLayerProperties(const VkEnumerateInstanceLayerPropertiesChain *chain,
6822                                                                           uint32_t *pPropertyCount,
6823                                                                           VkLayerProperties *pProperties) {
6824    (void)chain;
6825    VkResult result = VK_SUCCESS;
6826    struct loader_layer_list instance_layer_list;
6827    struct loader_envvar_all_filters layer_filters = {0};
6828
6829    LOADER_PLATFORM_THREAD_ONCE(&once_init, loader_initialize);
6830
6831    uint32_t copy_size;
6832
6833    result = parse_layer_environment_var_filters(NULL, &layer_filters);
6834    if (VK_SUCCESS != result) {
6835        goto out;
6836    }
6837
6838    // Get layer libraries
6839    memset(&instance_layer_list, 0, sizeof(instance_layer_list));
6840    result = loader_scan_for_layers(NULL, &instance_layer_list, &layer_filters);
6841    if (VK_SUCCESS != result) {
6842        goto out;
6843    }
6844
6845    uint32_t active_layer_count = 0;
6846    for (uint32_t i = 0; i < instance_layer_list.count; i++) {
6847        if (instance_layer_list.list[i].settings_control_value == LOADER_SETTINGS_LAYER_CONTROL_ON ||
6848            instance_layer_list.list[i].settings_control_value == LOADER_SETTINGS_LAYER_CONTROL_DEFAULT) {
6849            active_layer_count++;
6850        }
6851    }
6852
6853    if (pProperties == NULL) {
6854        *pPropertyCount = active_layer_count;
6855        goto out;
6856    }
6857
6858    copy_size = (*pPropertyCount < active_layer_count) ? *pPropertyCount : active_layer_count;
6859    uint32_t output_properties_index = 0;
6860    for (uint32_t i = 0; i < copy_size; i++) {
6861        if (instance_layer_list.list[i].settings_control_value == LOADER_SETTINGS_LAYER_CONTROL_ON ||
6862            instance_layer_list.list[i].settings_control_value == LOADER_SETTINGS_LAYER_CONTROL_DEFAULT) {
6863            memcpy(&pProperties[output_properties_index], &instance_layer_list.list[i].info, sizeof(VkLayerProperties));
6864            output_properties_index++;
6865        }
6866    }
6867
6868    *pPropertyCount = copy_size;
6869
6870    if (copy_size < instance_layer_list.count) {
6871        result = VK_INCOMPLETE;
6872        goto out;
6873    }
6874
6875out:
6876
6877    loader_delete_layer_list_and_properties(NULL, &instance_layer_list);
6878    return result;
6879}
6880
6881// ---- Vulkan Core 1.1 terminators
6882
6883VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumeratePhysicalDeviceGroups(
6884    VkInstance instance, uint32_t *pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties *pPhysicalDeviceGroupProperties) {
6885    struct loader_instance *inst = (struct loader_instance *)instance;
6886
6887    VkResult res = VK_SUCCESS;
6888    struct loader_icd_term *icd_term;
6889    uint32_t total_count = 0;
6890    uint32_t cur_icd_group_count = 0;
6891    VkPhysicalDeviceGroupProperties **new_phys_dev_groups = NULL;
6892    struct loader_physical_device_group_term *local_phys_dev_groups = NULL;
6893    PFN_vkEnumeratePhysicalDeviceGroups fpEnumeratePhysicalDeviceGroups = NULL;
6894    struct loader_icd_physical_devices *sorted_phys_dev_array = NULL;
6895    uint32_t sorted_count = 0;
6896
6897    // For each ICD, query the number of physical device groups, and then get an
6898    // internal value for those physical devices.
6899    icd_term = inst->icd_terms;
6900    for (uint32_t icd_idx = 0; NULL != icd_term; icd_term = icd_term->next, icd_idx++) {
6901        cur_icd_group_count = 0;
6902
6903        // Get the function pointer to use to call into the ICD. This could be the core or KHR version
6904        if (inst->enabled_known_extensions.khr_device_group_creation) {
6905            fpEnumeratePhysicalDeviceGroups = icd_term->dispatch.EnumeratePhysicalDeviceGroupsKHR;
6906        } else {
6907            fpEnumeratePhysicalDeviceGroups = icd_term->dispatch.EnumeratePhysicalDeviceGroups;
6908        }
6909
6910        if (NULL == fpEnumeratePhysicalDeviceGroups) {
6911            // Treat each ICD's GPU as it's own group if the extension isn't supported
6912            res = icd_term->dispatch.EnumeratePhysicalDevices(icd_term->instance, &cur_icd_group_count, NULL);
6913            if (res != VK_SUCCESS) {
6914                loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
6915                           "terminator_EnumeratePhysicalDeviceGroups:  Failed during dispatch call of \'EnumeratePhysicalDevices\' "
6916                           "to ICD %d to get plain phys dev count.",
6917                           icd_idx);
6918                continue;
6919            }
6920        } else {
6921            // Query the actual group info
6922            res = fpEnumeratePhysicalDeviceGroups(icd_term->instance, &cur_icd_group_count, NULL);
6923            if (res != VK_SUCCESS) {
6924                loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
6925                           "terminator_EnumeratePhysicalDeviceGroups:  Failed during dispatch call of "
6926                           "\'EnumeratePhysicalDeviceGroups\' to ICD %d to get count.",
6927                           icd_idx);
6928                continue;
6929            }
6930        }
6931        total_count += cur_icd_group_count;
6932    }
6933
6934    // If GPUs not sorted yet, look through them and generate list of all available GPUs
6935    if (0 == total_count || 0 == inst->total_gpu_count) {
6936        res = setup_loader_term_phys_devs(inst);
6937        if (VK_SUCCESS != res) {
6938            goto out;
6939        }
6940    }
6941
6942    if (NULL != pPhysicalDeviceGroupProperties) {
6943        // Create an array for the new physical device groups, which will be stored
6944        // in the instance for the Terminator code.
6945        new_phys_dev_groups = (VkPhysicalDeviceGroupProperties **)loader_instance_heap_calloc(
6946            inst, total_count * sizeof(VkPhysicalDeviceGroupProperties *), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
6947        if (NULL == new_phys_dev_groups) {
6948            loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
6949                       "terminator_EnumeratePhysicalDeviceGroups:  Failed to allocate new physical device group array of size %d",
6950                       total_count);
6951            res = VK_ERROR_OUT_OF_HOST_MEMORY;
6952            goto out;
6953        }
6954
6955        // Create a temporary array (on the stack) to keep track of the
6956        // returned VkPhysicalDevice values.
6957        local_phys_dev_groups = loader_stack_alloc(sizeof(struct loader_physical_device_group_term) * total_count);
6958        // Initialize the memory to something valid
6959        memset(local_phys_dev_groups, 0, sizeof(struct loader_physical_device_group_term) * total_count);
6960
6961#if defined(_WIN32)
6962        // Get the physical devices supported by platform sorting mechanism into a separate list
6963        res = windows_read_sorted_physical_devices(inst, &sorted_count, &sorted_phys_dev_array);
6964        if (VK_SUCCESS != res) {
6965            goto out;
6966        }
6967#endif
6968
6969        cur_icd_group_count = 0;
6970        icd_term = inst->icd_terms;
6971        for (uint8_t icd_idx = 0; NULL != icd_term; icd_term = icd_term->next, icd_idx++) {
6972            uint32_t count_this_time = total_count - cur_icd_group_count;
6973
6974            // Get the function pointer to use to call into the ICD. This could be the core or KHR version
6975            if (inst->enabled_known_extensions.khr_device_group_creation) {
6976                fpEnumeratePhysicalDeviceGroups = icd_term->dispatch.EnumeratePhysicalDeviceGroupsKHR;
6977            } else {
6978                fpEnumeratePhysicalDeviceGroups = icd_term->dispatch.EnumeratePhysicalDeviceGroups;
6979            }
6980
6981            if (NULL == fpEnumeratePhysicalDeviceGroups) {
6982                icd_term->dispatch.EnumeratePhysicalDevices(icd_term->instance, &count_this_time, NULL);
6983
6984                VkPhysicalDevice *phys_dev_array = loader_stack_alloc(sizeof(VkPhysicalDevice) * count_this_time);
6985                if (NULL == phys_dev_array) {
6986                    loader_log(
6987                        inst, VULKAN_LOADER_ERROR_BIT, 0,
6988                        "terminator_EnumeratePhysicalDeviceGroups:  Failed to allocate local physical device array of size %d",
6989                        count_this_time);
6990                    res = VK_ERROR_OUT_OF_HOST_MEMORY;
6991                    goto out;
6992                }
6993
6994                res = icd_term->dispatch.EnumeratePhysicalDevices(icd_term->instance, &count_this_time, phys_dev_array);
6995                if (res != VK_SUCCESS) {
6996                    loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
6997                               "terminator_EnumeratePhysicalDeviceGroups:  Failed during dispatch call of "
6998                               "\'EnumeratePhysicalDevices\' to ICD %d to get plain phys dev count.",
6999                               icd_idx);
7000                    goto out;
7001                }
7002
7003                // Add each GPU as it's own group
7004                for (uint32_t indiv_gpu = 0; indiv_gpu < count_this_time; indiv_gpu++) {
7005                    uint32_t cur_index = indiv_gpu + cur_icd_group_count;
7006                    local_phys_dev_groups[cur_index].this_icd_term = icd_term;
7007                    local_phys_dev_groups[cur_index].icd_index = icd_idx;
7008                    local_phys_dev_groups[cur_index].group_props.physicalDeviceCount = 1;
7009                    local_phys_dev_groups[cur_index].group_props.physicalDevices[0] = phys_dev_array[indiv_gpu];
7010                }
7011
7012            } else {
7013                res = fpEnumeratePhysicalDeviceGroups(icd_term->instance, &count_this_time, NULL);
7014                if (res != VK_SUCCESS) {
7015                    loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
7016                               "terminator_EnumeratePhysicalDeviceGroups:  Failed during dispatch call of "
7017                               "\'EnumeratePhysicalDeviceGroups\' to ICD %d to get group count.",
7018                               icd_idx);
7019                    goto out;
7020                }
7021                if (cur_icd_group_count + count_this_time < *pPhysicalDeviceGroupCount) {
7022                    // The total amount is still less than the amount of physical device group data passed in
7023                    // by the callee.  Therefore, we don't have to allocate any temporary structures and we
7024                    // can just use the data that was passed in.
7025                    res = fpEnumeratePhysicalDeviceGroups(icd_term->instance, &count_this_time,
7026                                                          &pPhysicalDeviceGroupProperties[cur_icd_group_count]);
7027                    if (res != VK_SUCCESS) {
7028                        loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
7029                                   "terminator_EnumeratePhysicalDeviceGroups:  Failed during dispatch call of "
7030                                   "\'EnumeratePhysicalDeviceGroups\' to ICD %d to get group information.",
7031                                   icd_idx);
7032                        goto out;
7033                    }
7034                    for (uint32_t group = 0; group < count_this_time; ++group) {
7035                        uint32_t cur_index = group + cur_icd_group_count;
7036                        local_phys_dev_groups[cur_index].group_props = pPhysicalDeviceGroupProperties[cur_index];
7037                        local_phys_dev_groups[cur_index].this_icd_term = icd_term;
7038                        local_phys_dev_groups[cur_index].icd_index = icd_idx;
7039                    }
7040                } else {
7041                    // There's not enough space in the callee's allocated pPhysicalDeviceGroupProperties structs,
7042                    // so we have to allocate temporary versions to collect all the data.  However, we need to make
7043                    // sure that at least the ones we do query utilize any pNext data in the callee's version.
7044                    VkPhysicalDeviceGroupProperties *tmp_group_props =
7045                        loader_stack_alloc(count_this_time * sizeof(VkPhysicalDeviceGroupProperties));
7046                    for (uint32_t group = 0; group < count_this_time; group++) {
7047                        tmp_group_props[group].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES;
7048                        uint32_t cur_index = group + cur_icd_group_count;
7049                        if (*pPhysicalDeviceGroupCount > cur_index) {
7050                            tmp_group_props[group].pNext = pPhysicalDeviceGroupProperties[cur_index].pNext;
7051                        } else {
7052                            tmp_group_props[group].pNext = NULL;
7053                        }
7054                        tmp_group_props[group].subsetAllocation = false;
7055                    }
7056
7057                    res = fpEnumeratePhysicalDeviceGroups(icd_term->instance, &count_this_time, tmp_group_props);
7058                    if (res != VK_SUCCESS) {
7059                        loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
7060                                   "terminator_EnumeratePhysicalDeviceGroups:  Failed during dispatch call of "
7061                                   "\'EnumeratePhysicalDeviceGroups\' to ICD %d  to get group information for temp data.",
7062                                   icd_idx);
7063                        goto out;
7064                    }
7065                    for (uint32_t group = 0; group < count_this_time; ++group) {
7066                        uint32_t cur_index = group + cur_icd_group_count;
7067                        local_phys_dev_groups[cur_index].group_props = tmp_group_props[group];
7068                        local_phys_dev_groups[cur_index].this_icd_term = icd_term;
7069                        local_phys_dev_groups[cur_index].icd_index = icd_idx;
7070                    }
7071                }
7072                if (VK_SUCCESS != res) {
7073                    loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
7074                               "terminator_EnumeratePhysicalDeviceGroups:  Failed during dispatch call of "
7075                               "\'EnumeratePhysicalDeviceGroups\' to ICD %d to get content.",
7076                               icd_idx);
7077                    goto out;
7078                }
7079            }
7080
7081            cur_icd_group_count += count_this_time;
7082        }
7083
7084#if defined(LOADER_ENABLE_LINUX_SORT)
7085        if (is_linux_sort_enabled(inst)) {
7086            // Get the physical devices supported by platform sorting mechanism into a separate list
7087            res = linux_sort_physical_device_groups(inst, total_count, local_phys_dev_groups);
7088        }
7089#elif defined(_WIN32)
7090        // The Windows sorting information is only on physical devices.  We need to take that and convert it to the group
7091        // information if it's present.
7092        if (sorted_count > 0) {
7093            res =
7094                windows_sort_physical_device_groups(inst, total_count, local_phys_dev_groups, sorted_count, sorted_phys_dev_array);
7095        }
7096#endif  // LOADER_ENABLE_LINUX_SORT
7097
7098        // Just to be safe, make sure we successfully completed setup_loader_term_phys_devs above
7099        // before attempting to do the following.  By verifying that setup_loader_term_phys_devs ran
7100        // first, it guarantees that each physical device will have a loader-specific handle.
7101        if (NULL != inst->phys_devs_term) {
7102            for (uint32_t group = 0; group < total_count; group++) {
7103                for (uint32_t group_gpu = 0; group_gpu < local_phys_dev_groups[group].group_props.physicalDeviceCount;
7104                     group_gpu++) {
7105                    bool found = false;
7106                    for (uint32_t term_gpu = 0; term_gpu < inst->phys_dev_count_term; term_gpu++) {
7107                        if (local_phys_dev_groups[group].group_props.physicalDevices[group_gpu] ==
7108                            inst->phys_devs_term[term_gpu]->phys_dev) {
7109                            local_phys_dev_groups[group].group_props.physicalDevices[group_gpu] =
7110                                (VkPhysicalDevice)inst->phys_devs_term[term_gpu];
7111                            found = true;
7112                            break;
7113                        }
7114                    }
7115                    if (!found) {
7116                        loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
7117                                   "terminator_EnumeratePhysicalDeviceGroups:  Failed to find GPU %d in group %d returned by "
7118                                   "\'EnumeratePhysicalDeviceGroups\' in list returned by \'EnumeratePhysicalDevices\'",
7119                                   group_gpu, group);
7120                        res = VK_ERROR_INITIALIZATION_FAILED;
7121                        goto out;
7122                    }
7123                }
7124            }
7125        }
7126
7127        uint32_t idx = 0;
7128
7129        // Copy or create everything to fill the new array of physical device groups
7130        for (uint32_t group = 0; group < total_count; group++) {
7131            // Skip groups which have been included through sorting
7132            if (local_phys_dev_groups[group].group_props.physicalDeviceCount == 0) {
7133                continue;
7134            }
7135
7136            // Find the VkPhysicalDeviceGroupProperties object in local_phys_dev_groups
7137            VkPhysicalDeviceGroupProperties *group_properties = &local_phys_dev_groups[group].group_props;
7138
7139            // Check if this physical device group with the same contents is already in the old buffer
7140            for (uint32_t old_idx = 0; old_idx < inst->phys_dev_group_count_term; old_idx++) {
7141                if (NULL != group_properties && NULL != inst->phys_dev_groups_term[old_idx] &&
7142                    group_properties->physicalDeviceCount == inst->phys_dev_groups_term[old_idx]->physicalDeviceCount) {
7143                    bool found_all_gpus = true;
7144                    for (uint32_t old_gpu = 0; old_gpu < inst->phys_dev_groups_term[old_idx]->physicalDeviceCount; old_gpu++) {
7145                        bool found_gpu = false;
7146                        for (uint32_t new_gpu = 0; new_gpu < group_properties->physicalDeviceCount; new_gpu++) {
7147                            if (group_properties->physicalDevices[new_gpu] ==
7148                                inst->phys_dev_groups_term[old_idx]->physicalDevices[old_gpu]) {
7149                                found_gpu = true;
7150                                break;
7151                            }
7152                        }
7153
7154                        if (!found_gpu) {
7155                            found_all_gpus = false;
7156                            break;
7157                        }
7158                    }
7159                    if (!found_all_gpus) {
7160                        continue;
7161                    } else {
7162                        new_phys_dev_groups[idx] = inst->phys_dev_groups_term[old_idx];
7163                        break;
7164                    }
7165                }
7166            }
7167            // If this physical device group isn't in the old buffer, create it
7168            if (group_properties != NULL && NULL == new_phys_dev_groups[idx]) {
7169                new_phys_dev_groups[idx] = (VkPhysicalDeviceGroupProperties *)loader_instance_heap_alloc(
7170                    inst, sizeof(VkPhysicalDeviceGroupProperties), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
7171                if (NULL == new_phys_dev_groups[idx]) {
7172                    loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
7173                               "terminator_EnumeratePhysicalDeviceGroups:  Failed to allocate physical device group Terminator "
7174                               "object %d",
7175                               idx);
7176                    total_count = idx;
7177                    res = VK_ERROR_OUT_OF_HOST_MEMORY;
7178                    goto out;
7179                }
7180                memcpy(new_phys_dev_groups[idx], group_properties, sizeof(VkPhysicalDeviceGroupProperties));
7181            }
7182
7183            ++idx;
7184        }
7185    }
7186
7187out:
7188
7189    if (NULL != pPhysicalDeviceGroupProperties) {
7190        if (VK_SUCCESS != res) {
7191            if (NULL != new_phys_dev_groups) {
7192                // We've encountered an error, so we should free the new buffers.
7193                for (uint32_t i = 0; i < total_count; i++) {
7194                    // If an OOM occurred inside the copying of the new physical device groups into the existing array will
7195                    // leave some of the old physical device groups in the array which may have been copied into the new array,
7196                    // leading to them being freed twice. To avoid this we just make sure to not delete physical device groups
7197                    // which were copied.
7198                    bool found = false;
7199                    if (NULL != inst->phys_devs_term) {
7200                        for (uint32_t old_idx = 0; old_idx < inst->phys_dev_group_count_term; old_idx++) {
7201                            if (new_phys_dev_groups[i] == inst->phys_dev_groups_term[old_idx]) {
7202                                found = true;
7203                                break;
7204                            }
7205                        }
7206                    }
7207                    if (!found) {
7208                        loader_instance_heap_free(inst, new_phys_dev_groups[i]);
7209                    }
7210                }
7211                loader_instance_heap_free(inst, new_phys_dev_groups);
7212            }
7213        } else {
7214            if (NULL != inst->phys_dev_groups_term) {
7215                // Free everything in the old array that was not copied into the new array
7216                // here.  We can't attempt to do that before here since the previous loop
7217                // looking before the "out:" label may hit an out of memory condition resulting
7218                // in memory leaking.
7219                for (uint32_t i = 0; i < inst->phys_dev_group_count_term; i++) {
7220                    bool found = false;
7221                    for (uint32_t j = 0; j < total_count; j++) {
7222                        if (inst->phys_dev_groups_term[i] == new_phys_dev_groups[j]) {
7223                            found = true;
7224                            break;
7225                        }
7226                    }
7227                    if (!found) {
7228                        loader_instance_heap_free(inst, inst->phys_dev_groups_term[i]);
7229                    }
7230                }
7231                loader_instance_heap_free(inst, inst->phys_dev_groups_term);
7232            }
7233
7234            // Swap in the new physical device group list
7235            inst->phys_dev_group_count_term = total_count;
7236            inst->phys_dev_groups_term = new_phys_dev_groups;
7237        }
7238
7239        if (sorted_phys_dev_array != NULL) {
7240            for (uint32_t i = 0; i < sorted_count; ++i) {
7241                if (sorted_phys_dev_array[i].device_count > 0 && sorted_phys_dev_array[i].physical_devices != NULL) {
7242                    loader_instance_heap_free(inst, sorted_phys_dev_array[i].physical_devices);
7243                }
7244            }
7245            loader_instance_heap_free(inst, sorted_phys_dev_array);
7246        }
7247
7248        uint32_t copy_count = inst->phys_dev_group_count_term;
7249        if (NULL != pPhysicalDeviceGroupProperties) {
7250            if (copy_count > *pPhysicalDeviceGroupCount) {
7251                copy_count = *pPhysicalDeviceGroupCount;
7252                loader_log(inst, VULKAN_LOADER_INFO_BIT, 0,
7253                           "terminator_EnumeratePhysicalDeviceGroups : Trimming device count from %d to %d.",
7254                           inst->phys_dev_group_count_term, copy_count);
7255                res = VK_INCOMPLETE;
7256            }
7257
7258            for (uint32_t i = 0; i < copy_count; i++) {
7259                memcpy(&pPhysicalDeviceGroupProperties[i], inst->phys_dev_groups_term[i], sizeof(VkPhysicalDeviceGroupProperties));
7260            }
7261        }
7262
7263        *pPhysicalDeviceGroupCount = copy_count;
7264
7265    } else {
7266        *pPhysicalDeviceGroupCount = total_count;
7267    }
7268    return res;
7269}
7270