Coverage Report

Created: 2026-07-16 07:04

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