Coverage Report

Created: 2025-08-25 06:16

/src/vulkan-loader/loader/settings.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 *
3
 * Copyright (c) 2023 The Khronos Group Inc.
4
 * Copyright (c) 2023 Valve Corporation
5
 * Copyright (c) 2023 LunarG, Inc.
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 *
19
 *
20
 * Author: Charles Giessen <charles@lunarg.com>
21
 *
22
 */
23
24
#include "settings.h"
25
26
#include "allocation.h"
27
#include "cJSON.h"
28
#include "loader.h"
29
#include "loader_environment.h"
30
#include "loader_json.h"
31
#if defined(WIN32)
32
#include "loader_windows.h"
33
#endif
34
#include "log.h"
35
#include "stack_allocation.h"
36
#include "vk_loader_platform.h"
37
38
loader_platform_thread_mutex global_loader_settings_lock;
39
loader_settings global_loader_settings;
40
41
44.5k
void free_layer_configuration(const struct loader_instance* inst, loader_settings_layer_configuration* layer_configuration) {
42
44.5k
    loader_instance_heap_free(inst, layer_configuration->name);
43
44.5k
    loader_instance_heap_free(inst, layer_configuration->path);
44
44.5k
    memset(layer_configuration, 0, sizeof(loader_settings_layer_configuration));
45
44.5k
}
46
47
0
void free_driver_configuration(const struct loader_instance* inst, loader_settings_driver_configuration* driver_configuration) {
48
0
    loader_instance_heap_free(inst, driver_configuration->path);
49
0
    memset(driver_configuration, 0, sizeof(loader_settings_driver_configuration));
50
0
}
51
52
0
void free_device_configuration(const struct loader_instance* inst, loader_settings_device_configuration* device_configuration) {
53
0
    (void)inst;
54
0
    memset(device_configuration, 0, sizeof(loader_settings_device_configuration));
55
0
}
56
57
7.50k
void free_loader_settings(const struct loader_instance* inst, loader_settings* settings) {
58
7.50k
    if (NULL != settings->layer_configurations) {
59
30.9k
        for (uint32_t i = 0; i < settings->layer_configuration_count; i++) {
60
30.0k
            free_layer_configuration(inst, &settings->layer_configurations[i]);
61
30.0k
        }
62
946
        loader_instance_heap_free(inst, settings->layer_configurations);
63
946
    }
64
7.50k
    if (NULL != settings->additional_drivers) {
65
0
        for (uint32_t i = 0; i < settings->additional_driver_count; i++) {
66
0
            free_driver_configuration(inst, &settings->additional_drivers[i]);
67
0
        }
68
0
        loader_instance_heap_free(inst, settings->additional_drivers);
69
0
    }
70
7.50k
    if (NULL != settings->device_configurations) {
71
0
        for (uint32_t i = 0; i < settings->device_configuration_count; i++) {
72
0
            free_device_configuration(inst, &settings->device_configurations[i]);
73
0
        }
74
0
        loader_instance_heap_free(inst, settings->device_configurations);
75
0
    }
76
7.50k
    loader_instance_heap_free(inst, settings->settings_file_path);
77
7.50k
    memset(settings, 0, sizeof(loader_settings));
78
7.50k
}
79
80
32.4k
loader_settings_layer_control parse_control_string(char* control_string) {
81
32.4k
    loader_settings_layer_control layer_control = LOADER_SETTINGS_LAYER_CONTROL_DEFAULT;
82
32.4k
    if (strcmp(control_string, "auto") == 0)
83
374
        layer_control = LOADER_SETTINGS_LAYER_CONTROL_DEFAULT;
84
32.0k
    else if (strcmp(control_string, "on") == 0)
85
524
        layer_control = LOADER_SETTINGS_LAYER_CONTROL_ON;
86
31.5k
    else if (strcmp(control_string, "off") == 0)
87
17.5k
        layer_control = LOADER_SETTINGS_LAYER_CONTROL_OFF;
88
13.9k
    else if (strcmp(control_string, "unordered_layer_location") == 0)
89
11.8k
        layer_control = LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION;
90
32.4k
    return layer_control;
91
32.4k
}
92
93
30.0k
const char* loader_settings_layer_control_to_string(loader_settings_layer_control control) {
94
30.0k
    switch (control) {
95
1.84k
        case (LOADER_SETTINGS_LAYER_CONTROL_DEFAULT):
96
1.84k
            return "auto";
97
475
        case (LOADER_SETTINGS_LAYER_CONTROL_ON):
98
475
            return "on";
99
15.8k
        case (LOADER_SETTINGS_LAYER_CONTROL_OFF):
100
15.8k
            return "off";
101
11.8k
        case (LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION):
102
11.8k
            return "unordered_layer_location";
103
0
        default:
104
0
            return "UNKNOWN_LAYER_CONTROl";
105
30.0k
    }
106
30.0k
}
107
108
659
uint32_t parse_log_filters_from_strings(struct loader_string_list* log_filters) {
109
659
    uint32_t filters = 0;
110
207k
    for (uint32_t i = 0; i < log_filters->count; i++) {
111
206k
        if (strcmp(log_filters->list[i], "all") == 0)
112
468
            filters |= VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_PERF_BIT | VULKAN_LOADER_ERROR_BIT |
113
468
                       VULKAN_LOADER_DEBUG_BIT | VULKAN_LOADER_LAYER_BIT | VULKAN_LOADER_DRIVER_BIT | VULKAN_LOADER_VALIDATION_BIT;
114
205k
        else if (strcmp(log_filters->list[i], "info") == 0)
115
432
            filters |= VULKAN_LOADER_INFO_BIT;
116
205k
        else if (strcmp(log_filters->list[i], "warn") == 0)
117
7.34k
            filters |= VULKAN_LOADER_WARN_BIT;
118
198k
        else if (strcmp(log_filters->list[i], "perf") == 0)
119
13.2k
            filters |= VULKAN_LOADER_PERF_BIT;
120
184k
        else if (strcmp(log_filters->list[i], "error") == 0)
121
224
            filters |= VULKAN_LOADER_ERROR_BIT;
122
184k
        else if (strcmp(log_filters->list[i], "debug") == 0)
123
1.25k
            filters |= VULKAN_LOADER_DEBUG_BIT;
124
183k
        else if (strcmp(log_filters->list[i], "layer") == 0)
125
942
            filters |= VULKAN_LOADER_LAYER_BIT;
126
182k
        else if (strcmp(log_filters->list[i], "driver") == 0)
127
1.04k
            filters |= VULKAN_LOADER_DRIVER_BIT;
128
181k
        else if (strcmp(log_filters->list[i], "validation") == 0)
129
203
            filters |= VULKAN_LOADER_VALIDATION_BIT;
130
206k
    }
131
659
    return filters;
132
659
}
133
134
0
bool parse_json_enable_disable_option(cJSON* object) {
135
0
    char* str = loader_cJSON_GetStringValue(object);
136
0
    if (NULL == str) {
137
0
        return false;
138
0
    }
139
0
    bool enable = false;
140
0
    if (strcmp(str, "enabled") == 0) {
141
0
        enable = true;
142
0
    }
143
0
    return enable;
144
0
}
145
146
VkResult parse_layer_configuration(const struct loader_instance* inst, cJSON* layer_configuration_json,
147
32.4k
                                   loader_settings_layer_configuration* layer_configuration) {
148
32.4k
    char* control_string = NULL;
149
32.4k
    VkResult res = loader_parse_json_string(layer_configuration_json, "control", &control_string);
150
32.4k
    if (res != VK_SUCCESS) {
151
18
        goto out;
152
18
    }
153
32.4k
    layer_configuration->control = parse_control_string(control_string);
154
32.4k
    loader_instance_heap_free(inst, control_string);
155
156
    // If that is the only value - do no further parsing
157
32.4k
    if (layer_configuration->control == LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION) {
158
11.8k
        goto out;
159
11.8k
    }
160
161
20.5k
    res = loader_parse_json_string(layer_configuration_json, "name", &(layer_configuration->name));
162
20.5k
    if (res != VK_SUCCESS) {
163
226
        goto out;
164
226
    }
165
166
20.3k
    res = loader_parse_json_string(layer_configuration_json, "path", &(layer_configuration->path));
167
20.3k
    if (res != VK_SUCCESS) {
168
7
        goto out;
169
7
    }
170
171
20.3k
    cJSON* treat_as_implicit_manifest = loader_cJSON_GetObjectItem(layer_configuration_json, "treat_as_implicit_manifest");
172
20.3k
    if (treat_as_implicit_manifest && treat_as_implicit_manifest->type == cJSON_True) {
173
177
        layer_configuration->treat_as_implicit_manifest = true;
174
177
    }
175
32.4k
out:
176
32.4k
    if (VK_SUCCESS != res) {
177
251
        free_layer_configuration(inst, layer_configuration);
178
251
    }
179
32.4k
    return res;
180
20.3k
}
181
182
1.82k
VkResult parse_layer_configurations(const struct loader_instance* inst, cJSON* settings_object, loader_settings* loader_settings) {
183
1.82k
    VkResult res = VK_SUCCESS;
184
185
1.82k
    cJSON* layer_configurations = loader_cJSON_GetObjectItem(settings_object, "layers");
186
    // If the layers object isn't present, return early with success to allow the settings file to still apply
187
1.82k
    if (NULL == layer_configurations) {
188
613
        return VK_SUCCESS;
189
613
    }
190
191
1.20k
    uint32_t layer_configurations_count = loader_cJSON_GetArraySize(layer_configurations);
192
1.20k
    if (layer_configurations_count == 0) {
193
5
        return VK_SUCCESS;
194
5
    }
195
196
1.20k
    loader_settings->layer_configuration_count = layer_configurations_count;
197
198
1.20k
    loader_settings->layer_configurations = loader_instance_heap_calloc(
199
1.20k
        inst, sizeof(loader_settings_layer_configuration) * layer_configurations_count, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
200
1.20k
    if (NULL == loader_settings->layer_configurations) {
201
0
        res = VK_ERROR_OUT_OF_HOST_MEMORY;
202
0
        goto out;
203
0
    }
204
205
1.20k
    cJSON* layer = NULL;
206
1.20k
    size_t i = 0;
207
32.4k
    cJSON_ArrayForEach(layer, layer_configurations) {
208
32.4k
        if (layer->type != cJSON_Object) {
209
7
            res = VK_ERROR_INITIALIZATION_FAILED;
210
7
            goto out;
211
7
        }
212
32.4k
        res = parse_layer_configuration(inst, layer, &(loader_settings->layer_configurations[i++]));
213
32.4k
        if (VK_SUCCESS != res) {
214
251
            goto out;
215
251
        }
216
32.4k
    }
217
1.20k
out:
218
1.20k
    if (res != VK_SUCCESS) {
219
258
        if (loader_settings->layer_configurations) {
220
14.5k
            for (size_t index = 0; index < loader_settings->layer_configuration_count; index++) {
221
14.2k
                free_layer_configuration(inst, &(loader_settings->layer_configurations[index]));
222
14.2k
            }
223
258
            loader_settings->layer_configuration_count = 0;
224
258
            loader_instance_heap_free(inst, loader_settings->layer_configurations);
225
258
            loader_settings->layer_configurations = NULL;
226
258
        }
227
258
    }
228
229
1.20k
    return res;
230
1.20k
}
231
232
VkResult parse_additional_driver(const struct loader_instance* inst, cJSON* additional_driver_json,
233
0
                                 loader_settings_driver_configuration* additional_driver) {
234
0
    VkResult res = VK_SUCCESS;
235
0
    res = loader_parse_json_string(additional_driver_json, "path", &(additional_driver->path));
236
0
    if (res != VK_SUCCESS) {
237
0
        goto out;
238
0
    }
239
0
out:
240
0
    if (res != VK_SUCCESS) {
241
0
        free_driver_configuration(inst, additional_driver);
242
0
    }
243
0
    return res;
244
0
}
245
246
1.82k
VkResult parse_additional_drivers(const struct loader_instance* inst, cJSON* settings_object, loader_settings* loader_settings) {
247
1.82k
    VkResult res = VK_SUCCESS;
248
249
1.82k
    cJSON* additional_drivers_use_exclusively_json =
250
1.82k
        loader_cJSON_GetObjectItem(settings_object, "additional_drivers_use_exclusively");
251
1.82k
    if (additional_drivers_use_exclusively_json && additional_drivers_use_exclusively_json->type == cJSON_True) {
252
0
        loader_settings->additional_drivers_use_exclusively = true;
253
0
    }
254
255
1.82k
    cJSON* additional_drivers_json = loader_cJSON_GetObjectItem(settings_object, "additional_drivers");
256
1.82k
    if (NULL == additional_drivers_json) {
257
1.82k
        return VK_SUCCESS;
258
1.82k
    }
259
260
0
    uint32_t additional_driver_count = loader_cJSON_GetArraySize(additional_drivers_json);
261
0
    if (additional_driver_count == 0) {
262
0
        return VK_SUCCESS;
263
0
    }
264
265
0
    loader_settings->additional_driver_count = additional_driver_count;
266
267
0
    loader_settings->additional_drivers = loader_instance_heap_calloc(
268
0
        inst, sizeof(loader_settings_layer_configuration) * additional_driver_count, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
269
0
    if (NULL == loader_settings->additional_drivers) {
270
0
        res = VK_ERROR_OUT_OF_HOST_MEMORY;
271
0
        goto out;
272
0
    }
273
274
0
    cJSON* driver = NULL;
275
0
    size_t i = 0;
276
0
    cJSON_ArrayForEach(driver, additional_drivers_json) {
277
0
        if (driver->type != cJSON_Object) {
278
0
            res = VK_ERROR_INITIALIZATION_FAILED;
279
0
            goto out;
280
0
        }
281
0
        res = parse_additional_driver(inst, driver, &(loader_settings->additional_drivers[i++]));
282
0
        if (VK_SUCCESS != res) {
283
0
            goto out;
284
0
        }
285
0
    }
286
0
out:
287
0
    if (res != VK_SUCCESS) {
288
0
        if (loader_settings->additional_drivers) {
289
0
            for (size_t index = 0; index < loader_settings->additional_driver_count; index++) {
290
0
                free_driver_configuration(inst, &(loader_settings->additional_drivers[index]));
291
0
            }
292
0
            loader_settings->additional_driver_count = 0;
293
0
            loader_instance_heap_free(inst, loader_settings->additional_drivers);
294
0
            loader_settings->additional_drivers = NULL;
295
0
        }
296
0
    }
297
0
    return res;
298
0
}
299
300
VkResult parse_device_configuration(const struct loader_instance* inst, cJSON* device_configuration_json,
301
0
                                    loader_settings_device_configuration* device_configuration) {
302
0
    (void)inst;
303
0
    VkResult res = VK_SUCCESS;
304
0
    cJSON* deviceUUID_array = loader_cJSON_GetObjectItem(device_configuration_json, "deviceUUID");
305
0
    if (NULL == deviceUUID_array) {
306
0
        res = VK_ERROR_INITIALIZATION_FAILED;
307
0
        goto out;
308
0
    }
309
310
0
    if (deviceUUID_array->type != cJSON_Array) {
311
0
        res = VK_ERROR_INITIALIZATION_FAILED;
312
0
        goto out;
313
0
    }
314
0
    if (VK_UUID_SIZE != loader_cJSON_GetArraySize(deviceUUID_array)) {
315
0
        res = VK_ERROR_INITIALIZATION_FAILED;
316
0
        goto out;
317
0
    }
318
319
0
    cJSON* uuid_field = NULL;
320
0
    size_t i = 0;
321
0
    cJSON_ArrayForEach(uuid_field, deviceUUID_array) {
322
0
        if (uuid_field->type != cJSON_Number) {
323
0
            res = VK_ERROR_INITIALIZATION_FAILED;
324
0
            goto out;
325
0
        }
326
0
        if (uuid_field->valueint < 0 || uuid_field->valueint > 255) {
327
0
            res = VK_ERROR_INITIALIZATION_FAILED;
328
0
            goto out;
329
0
        }
330
0
        device_configuration->deviceUUID[i] = (uint8_t)uuid_field->valueint;
331
0
        i++;
332
0
    }
333
334
0
    VkResult deviceNameRes = loader_parse_json_string_to_existing_str(
335
0
        device_configuration_json, "deviceName", VK_MAX_PHYSICAL_DEVICE_NAME_SIZE, device_configuration->deviceName);
336
0
    if (VK_ERROR_OUT_OF_HOST_MEMORY == deviceNameRes) {
337
0
        res = deviceNameRes;
338
0
        goto out;
339
0
    }
340
0
out:
341
0
    if (res != VK_SUCCESS) {
342
0
        memset(device_configuration, 0, sizeof(loader_settings_device_configuration));
343
0
    }
344
0
    return res;
345
0
}
346
347
1.82k
VkResult parse_device_configurations(const struct loader_instance* inst, cJSON* settings_object, loader_settings* loader_settings) {
348
1.82k
    VkResult res = VK_SUCCESS;
349
350
1.82k
    cJSON* device_configurations = loader_cJSON_GetObjectItem(settings_object, "device_configurations");
351
1.82k
    if (NULL == device_configurations) {
352
1.82k
        return VK_SUCCESS;
353
1.82k
    }
354
355
0
    uint32_t device_configuration_count = loader_cJSON_GetArraySize(device_configurations);
356
0
    if (device_configuration_count == 0) {
357
0
        return VK_SUCCESS;
358
0
    }
359
360
0
    loader_settings->device_configuration_count = device_configuration_count;
361
362
0
    loader_settings->device_configurations = loader_instance_heap_calloc(
363
0
        inst, sizeof(loader_settings_device_configuration) * device_configuration_count, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
364
0
    if (NULL == loader_settings->device_configurations) {
365
0
        res = VK_ERROR_OUT_OF_HOST_MEMORY;
366
0
        goto out;
367
0
    }
368
369
0
    cJSON* device = NULL;
370
0
    size_t i = 0;
371
0
    cJSON_ArrayForEach(device, device_configurations) {
372
0
        if (device->type != cJSON_Object) {
373
0
            res = VK_ERROR_INITIALIZATION_FAILED;
374
0
            goto out;
375
0
        }
376
0
        res = parse_device_configuration(inst, device, &(loader_settings->device_configurations[i]));
377
0
        if (res == VK_ERROR_OUT_OF_HOST_MEMORY) {
378
0
            goto out;
379
0
        } else if (res != VK_SUCCESS) {
380
0
            continue;
381
0
        }
382
0
        i++;
383
0
    }
384
0
out:
385
0
    if (res != VK_SUCCESS) {
386
0
        if (loader_settings->device_configurations) {
387
0
            for (size_t index = 0; index < loader_settings->device_configuration_count; index++) {
388
0
                free_device_configuration(inst, &(loader_settings->device_configurations[index]));
389
0
            }
390
0
            loader_settings->device_configuration_count = 0;
391
0
            loader_instance_heap_free(inst, loader_settings->device_configurations);
392
0
            loader_settings->device_configurations = NULL;
393
0
        }
394
0
    }
395
0
    return res;
396
0
}
397
398
#if COMMON_UNIX_PLATFORMS
399
// Given a base and suffix path, determine if a file at that location exists, and if it is return success.
400
// Since base may contain multiple paths seperated by PATH_SEPARATOR, we must extract each segment and check segment + suffix
401
// individually
402
VkResult check_if_settings_path_exists(const struct loader_instance* inst, const char* base, const char* suffix,
403
30.3k
                                       char** settings_file_path) {
404
30.3k
    if (NULL == base || NULL == suffix) {
405
15.0k
        return VK_ERROR_INITIALIZATION_FAILED;
406
15.0k
    }
407
408
15.3k
    size_t base_len = strlen(base);
409
15.3k
    size_t suffix_len = strlen(suffix);
410
411
15.3k
    uint32_t start = 0;
412
15.3k
    uint32_t stop = 0;
413
23.3k
    while (base[start] != '\0' && start < base_len && stop < base_len) {
414
15.4k
        start = stop;
415
15.4k
        stop = start + 1;
416
64.4k
        while (base[stop] != PATH_SEPARATOR && base[stop] != '\0' && stop < base_len) {
417
49.0k
            stop++;
418
49.0k
        }
419
420
15.4k
        size_t segment_len = (stop - start);
421
15.4k
        if (segment_len <= 1) {
422
            // segment is *just* a PATH_SEPARATOR, skip it
423
0
            continue;
424
0
        }
425
15.4k
        size_t path_len = segment_len + suffix_len + 1;
426
15.4k
        *settings_file_path = loader_instance_heap_calloc(inst, path_len, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
427
15.4k
        if (NULL == *settings_file_path) {
428
0
            return VK_ERROR_OUT_OF_HOST_MEMORY;
429
0
        }
430
15.4k
        loader_strncpy(*settings_file_path, path_len, base + start, segment_len);
431
15.4k
        loader_strncat(*settings_file_path, path_len, suffix, suffix_len);
432
433
15.4k
        if (loader_platform_file_exists(*settings_file_path)) {
434
7.42k
            return VK_SUCCESS;
435
7.42k
        }
436
8.00k
        loader_instance_heap_free(inst, *settings_file_path);
437
8.00k
        *settings_file_path = NULL;
438
8.00k
    }
439
440
7.92k
    return VK_ERROR_INITIALIZATION_FAILED;
441
15.3k
}
442
443
// Follow the logic of read_data_files_in_search_paths but only look for "/vulkan/loader_settings.d/" VK_LOADER_SETTINGS_FILENAME
444
7.50k
VkResult get_unix_settings_path(const struct loader_instance* inst, char** settings_file_path) {
445
    // First, get XDG env-vars we use. Don't need to worry about free'ing because on linux getenv is non-allocating
446
7.50k
    char* xdg_config_home = loader_secure_getenv("XDG_CONFIG_HOME", inst);
447
7.50k
    char* xdg_config_dirs = loader_secure_getenv("XDG_CONFIG_DIRS", inst);
448
7.50k
    char* xdg_data_home = loader_secure_getenv("XDG_DATA_HOME", inst);
449
7.50k
    char* xdg_data_dirs = loader_secure_getenv("XDG_DATA_DIRS", inst);
450
451
    // Use fallback directories for xdg_config_dirs and xdg_data_dirs if they are NULL.
452
7.50k
#if !defined(__Fuchsia__) && !defined(__QNX__)
453
7.50k
    if (NULL == xdg_config_dirs || '\0' == xdg_config_dirs[0]) {
454
7.50k
        xdg_config_dirs = FALLBACK_CONFIG_DIRS;
455
7.50k
    }
456
7.50k
#endif
457
458
7.50k
#if !defined(__Fuchsia__) && !defined(__QNX__)
459
7.50k
    if (NULL == xdg_data_dirs || '\0' == xdg_data_dirs[0]) {
460
7.50k
        xdg_data_dirs = FALLBACK_DATA_DIRS;
461
7.50k
    }
462
7.50k
#endif
463
464
7.50k
    VkResult res = check_if_settings_path_exists(inst, xdg_config_home, "/vulkan/loader_settings.d/" VK_LOADER_SETTINGS_FILENAME,
465
7.50k
                                                 settings_file_path);
466
7.50k
    if (res == VK_SUCCESS) {
467
0
        return res;
468
0
    }
469
470
7.50k
    res = check_if_settings_path_exists(inst, xdg_data_home, "/vulkan/loader_settings.d/" VK_LOADER_SETTINGS_FILENAME,
471
7.50k
                                        settings_file_path);
472
7.50k
    if (res == VK_SUCCESS) {
473
0
        return res;
474
0
    }
475
476
    // Check home if either xdg_config_home or xdg_data_home wasn't set
477
7.50k
    char* home = loader_secure_getenv("HOME", inst);
478
7.50k
    if (home != NULL) {
479
7.50k
        if (NULL == xdg_config_home || '\0' == xdg_config_home[0]) {
480
7.50k
            res = check_if_settings_path_exists(inst, home, "/.config/vulkan/loader_settings.d/" VK_LOADER_SETTINGS_FILENAME,
481
7.50k
                                                settings_file_path);
482
7.50k
            if (res == VK_SUCCESS) {
483
0
                return res;
484
0
            }
485
7.50k
        }
486
7.50k
        if (NULL == xdg_data_home || '\0' == xdg_data_home[0]) {
487
7.50k
            res = check_if_settings_path_exists(inst, home, "/.local/share/vulkan/loader_settings.d/" VK_LOADER_SETTINGS_FILENAME,
488
7.50k
                                                settings_file_path);
489
7.50k
            if (res == VK_SUCCESS) {
490
7.42k
                return res;
491
7.42k
            }
492
7.50k
        }
493
7.50k
    }
494
495
83
    res = check_if_settings_path_exists(inst, xdg_config_dirs, "/vulkan/loader_settings.d/" VK_LOADER_SETTINGS_FILENAME,
496
83
                                        settings_file_path);
497
83
    if (res == VK_SUCCESS) {
498
0
        return res;
499
0
    }
500
501
83
    res = check_if_settings_path_exists(inst, SYSCONFDIR, "/vulkan/loader_settings.d/" VK_LOADER_SETTINGS_FILENAME,
502
83
                                        settings_file_path);
503
83
    if (res == VK_SUCCESS) {
504
0
        return res;
505
0
    }
506
83
#if defined(EXTRASYSCONFDIR)
507
508
83
    res = check_if_settings_path_exists(inst, EXTRASYSCONFDIR, "/vulkan/loader_settings.d/" VK_LOADER_SETTINGS_FILENAME,
509
83
                                        settings_file_path);
510
83
    if (res == VK_SUCCESS) {
511
0
        return res;
512
0
    }
513
83
#endif
514
83
    res = check_if_settings_path_exists(inst, xdg_data_dirs, "/vulkan/loader_settings.d/" VK_LOADER_SETTINGS_FILENAME,
515
83
                                        settings_file_path);
516
83
    if (res == VK_SUCCESS) {
517
0
        return res;
518
0
    }
519
520
83
    return VK_ERROR_INITIALIZATION_FAILED;
521
83
}
522
#endif
523
524
0
bool check_if_layer_configurations_are_equal(loader_settings_layer_configuration* a, loader_settings_layer_configuration* b) {
525
0
    if (!a->name || !b->name || 0 != strcmp(a->name, b->name)) {
526
0
        return false;
527
0
    }
528
0
    if (!a->path || !b->path || 0 != strcmp(a->path, b->path)) {
529
0
        return false;
530
0
    }
531
0
    return a->control == b->control;
532
0
}
533
534
0
bool check_if_driver_configurations_are_equal(loader_settings_driver_configuration* a, loader_settings_driver_configuration* b) {
535
0
    if (!a->path || !b->path || 0 != strcmp(a->path, b->path)) {
536
0
        return false;
537
0
    }
538
0
    return true;
539
0
}
540
541
0
bool check_if_device_configurations_are_equal(loader_settings_device_configuration* a, loader_settings_device_configuration* b) {
542
0
    for (uint32_t i = 0; i < VK_UUID_SIZE; i++) {
543
0
        if (a->deviceUUID[i] != b->deviceUUID[i]) return false;
544
0
    }
545
0
    return true;
546
0
}
547
548
0
bool check_if_settings_are_equal(loader_settings* a, loader_settings* b) {
549
    // If either pointer is null, return true
550
0
    if (NULL == a || NULL == b) return false;
551
0
    bool are_equal = true;
552
0
    are_equal &= a->settings_active == b->settings_active;
553
0
    are_equal &= a->has_unordered_layer_location == b->has_unordered_layer_location;
554
0
    are_equal &= a->debug_level == b->debug_level;
555
0
    are_equal &= a->layer_configuration_count == b->layer_configuration_count;
556
0
    are_equal &= a->additional_driver_count == b->additional_driver_count;
557
0
    are_equal &= a->device_configuration_count == b->device_configuration_count;
558
0
    if (!are_equal) return false;
559
0
    for (uint32_t i = 0; i < a->layer_configuration_count && i < b->layer_configuration_count; i++) {
560
0
        are_equal &= check_if_layer_configurations_are_equal(&a->layer_configurations[i], &b->layer_configurations[i]);
561
0
    }
562
0
    for (uint32_t i = 0; i < a->additional_driver_count && i < b->additional_driver_count; i++) {
563
0
        are_equal &= check_if_driver_configurations_are_equal(&a->additional_drivers[i], &b->additional_drivers[i]);
564
0
    }
565
0
    for (uint32_t i = 0; i < a->device_configuration_count && i < b->device_configuration_count; i++) {
566
0
        are_equal &= check_if_device_configurations_are_equal(&a->device_configurations[i], &b->device_configurations[i]);
567
0
    }
568
0
    return are_equal;
569
0
}
570
571
1.15k
void log_settings(const struct loader_instance* inst, loader_settings* settings) {
572
1.15k
    if (settings == NULL) {
573
0
        return;
574
0
    }
575
1.15k
    loader_log(inst, VULKAN_LOADER_INFO_BIT, 0, "Using layer configurations found in loader settings from %s",
576
1.15k
               settings->settings_file_path);
577
578
1.15k
    char cmd_line_msg[64] = {0};
579
1.15k
    size_t cmd_line_size = sizeof(cmd_line_msg);
580
581
1.15k
    cmd_line_msg[0] = '\0';
582
583
1.15k
    generate_debug_flag_str(settings->debug_level, cmd_line_size, cmd_line_msg);
584
1.15k
    if (strlen(cmd_line_msg)) {
585
280
        loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "Loader Settings Filters for Logging to Standard Error: %s", cmd_line_msg);
586
280
    }
587
588
1.15k
    loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "Layer Configurations count = %d", settings->layer_configuration_count);
589
31.1k
    for (uint32_t i = 0; i < settings->layer_configuration_count; i++) {
590
30.0k
        loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "---- Layer Configuration [%d] ----", i);
591
30.0k
        if (settings->layer_configurations[i].control != LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION) {
592
18.1k
            loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "Name: %s", settings->layer_configurations[i].name);
593
18.1k
            loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "Path: %s", settings->layer_configurations[i].path);
594
18.1k
            loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "Layer Type: %s",
595
18.1k
                       settings->layer_configurations[i].treat_as_implicit_manifest ? "Implicit" : "Explicit");
596
18.1k
        }
597
30.0k
        loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "Control: %s",
598
30.0k
                   loader_settings_layer_control_to_string(settings->layer_configurations[i].control));
599
30.0k
    }
600
1.15k
    if (settings->additional_driver_count > 0) {
601
0
        loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "----");
602
0
        loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "Use Additional Drivers Exclusively = %s",
603
0
                   settings->additional_drivers_use_exclusively ? "true" : "false");
604
0
        loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "Additional Driver Configurations count = %d",
605
0
                   settings->additional_driver_count);
606
0
        for (uint32_t i = 0; i < settings->additional_driver_count; i++) {
607
0
            loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "---- Driver Configuration [%d] ----", i);
608
0
            loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "Path: %s", settings->additional_drivers[i].path);
609
0
        }
610
0
    }
611
1.15k
    if (settings->device_configuration_count > 0) {
612
0
        loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "----");
613
0
        loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "Device Configurations count = %d", settings->device_configuration_count);
614
0
        for (uint32_t i = 0; i < settings->device_configuration_count; i++) {
615
0
            loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "---- Device Configuration [%d] ----", i);
616
0
            uint8_t* id = settings->device_configurations[i].deviceUUID;
617
0
            loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0,
618
0
                       "deviceUUID: %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", id[0], id[1], id[2],
619
0
                       id[3], id[4], id[5], id[6], id[7], id[8], id[9], id[10], id[11], id[12], id[13], id[14], id[15]);
620
0
            if ('\0' != settings->device_configurations[i].deviceName[0]) {
621
0
                loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "deviceName: %s", settings->device_configurations[i].deviceName);
622
0
            }
623
0
        }
624
0
    }
625
1.15k
    loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "---------------------------------");
626
1.15k
}
627
628
// Loads the vk_loader_settings.json file
629
// Returns VK_SUCCESS if it was found & was successfully parsed. Otherwise, it returns VK_ERROR_INITIALIZATION_FAILED if it
630
// wasn't found or failed to parse, and returns VK_ERROR_OUT_OF_HOST_MEMORY if it was unable to allocate enough memory.
631
7.50k
VkResult get_loader_settings(const struct loader_instance* inst, loader_settings* loader_settings) {
632
7.50k
    VkResult res = VK_SUCCESS;
633
7.50k
    cJSON* json = NULL;
634
7.50k
    char* file_format_version_string = NULL;
635
7.50k
    char* settings_file_path = NULL;
636
#if defined(WIN32)
637
    res = windows_get_loader_settings_file_path(inst, &settings_file_path);
638
    if (res != VK_SUCCESS) {
639
        loader_log(inst, VULKAN_LOADER_INFO_BIT, 0,
640
                   "No valid vk_loader_settings.json file found, no loader settings will be active");
641
        goto out;
642
    }
643
644
#elif COMMON_UNIX_PLATFORMS
645
    res = get_unix_settings_path(inst, &settings_file_path);
646
7.50k
    if (res != VK_SUCCESS) {
647
83
        loader_log(inst, VULKAN_LOADER_INFO_BIT, 0,
648
83
                   "No valid vk_loader_settings.json file found, no loader settings will be active");
649
83
        goto out;
650
83
    }
651
#else
652
#warning "Unsupported platform - must specify platform specific location for vk_loader_settings.json"
653
#endif
654
655
7.42k
    res = loader_get_json(inst, settings_file_path, &json);
656
    // Make sure sure the top level json value is an object
657
7.42k
    if (res != VK_SUCCESS || NULL == json || json->type != cJSON_Object) {
658
516
        goto out;
659
516
    }
660
661
6.90k
    res = loader_parse_json_string(json, "file_format_version", &file_format_version_string);
662
6.90k
    if (res != VK_SUCCESS) {
663
7
        if (res != VK_ERROR_OUT_OF_HOST_MEMORY) {
664
7
            loader_log(
665
7
                inst, VULKAN_LOADER_DEBUG_BIT, 0,
666
7
                "Loader settings file from %s missing required field file_format_version - no loader settings will be active",
667
7
                settings_file_path);
668
7
        }
669
7
        goto out;
670
7
    }
671
672
    // Because the file may contain either a "settings_array" or a single "settings" object, we need to create a cJSON so that we
673
    // can iterate on both cases with common code
674
6.89k
    cJSON settings_iter_parent = {0};
675
676
6.89k
    cJSON* settings_array = loader_cJSON_GetObjectItem(json, "settings_array");
677
6.89k
    cJSON* single_settings_object = loader_cJSON_GetObjectItem(json, "settings");
678
6.89k
    if (NULL != settings_array) {
679
2.02k
        memcpy(&settings_iter_parent, settings_array, sizeof(cJSON));
680
4.87k
    } else if (NULL != single_settings_object) {
681
2
        settings_iter_parent.child = single_settings_object;
682
4.87k
    } else if (settings_array == NULL && single_settings_object) {
683
0
        loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0,
684
0
                   "Loader settings file from %s missing required settings objects: Either one of the \"settings\" or "
685
0
                   "\"settings_array\" objects must be present - no loader settings will be active",
686
0
                   settings_file_path);
687
0
        res = VK_ERROR_INITIALIZATION_FAILED;
688
0
        goto out;
689
0
    }
690
691
    // Corresponds to the settings object that has no app keys
692
6.89k
    cJSON* global_settings = NULL;
693
    // Corresponds to the settings object which has a matching app key
694
6.89k
    cJSON* settings_to_use = NULL;
695
696
6.89k
    char current_process_path[1024];
697
6.89k
    bool valid_exe_path = NULL != loader_platform_executable_path(current_process_path, 1024);
698
699
6.89k
    cJSON* settings_object_iter = NULL;
700
6.89k
    cJSON_ArrayForEach(settings_object_iter, &settings_iter_parent) {
701
2.69k
        if (settings_object_iter->type != cJSON_Object) {
702
65
            loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0,
703
65
                       "Loader settings file from %s has a settings element that is not an object", settings_file_path);
704
65
            break;
705
65
        }
706
707
2.62k
        cJSON* app_keys = loader_cJSON_GetObjectItem(settings_object_iter, "app_keys");
708
2.62k
        if (NULL == app_keys) {
709
            // use the first 'global' settings that has no app keys as the global one
710
2.04k
            if (global_settings == NULL) {
711
1.82k
                global_settings = settings_object_iter;
712
1.82k
            }
713
2.04k
            continue;
714
2.04k
        }
715
        // No sense iterating if we couldn't get the executable path
716
581
        if (!valid_exe_path) {
717
0
            break;
718
0
        }
719
581
        cJSON* app_key = NULL;
720
1.14k
        cJSON_ArrayForEach(app_key, app_keys) {
721
1.14k
            char* app_key_str = loader_cJSON_GetStringValue(app_key);
722
1.14k
            if (app_key_str && strcmp(current_process_path, app_key_str) == 0) {
723
0
                settings_to_use = settings_object_iter;
724
0
                break;
725
0
            }
726
1.14k
        }
727
728
        // Break if we have found a matching current_process_path
729
581
        if (NULL != settings_to_use) {
730
0
            break;
731
0
        }
732
581
    }
733
734
    // No app specific settings match - either use global settings or exit
735
6.89k
    if (settings_to_use == NULL) {
736
6.89k
        if (global_settings == NULL) {
737
5.07k
            loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0,
738
5.07k
                       "Loader settings file from %s missing global settings and none of the app specific settings matched the "
739
5.07k
                       "current application - no loader settings will be active",
740
5.07k
                       settings_file_path);
741
5.07k
            goto out;  // No global settings were found - exit
742
5.07k
        } else {
743
1.82k
            settings_to_use = global_settings;  // Global settings are present - use it
744
1.82k
        }
745
6.89k
    }
746
747
    // optional
748
1.82k
    cJSON* stderr_filter = loader_cJSON_GetObjectItem(settings_to_use, "stderr_log");
749
1.82k
    if (NULL != stderr_filter) {
750
659
        struct loader_string_list stderr_log = {0};
751
659
        res = loader_parse_json_array_of_strings(inst, settings_to_use, "stderr_log", &stderr_log);
752
659
        if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
753
0
            goto out;
754
0
        }
755
659
        loader_settings->debug_level = parse_log_filters_from_strings(&stderr_log);
756
659
        free_string_list(inst, &stderr_log);
757
659
    }
758
759
    // optional
760
1.82k
    cJSON* logs_to_use = loader_cJSON_GetObjectItem(settings_to_use, "log_locations");
761
1.82k
    if (NULL != logs_to_use) {
762
38
        cJSON* log_element = NULL;
763
562
        cJSON_ArrayForEach(log_element, logs_to_use) {
764
            // bool is_valid = true;
765
562
            struct loader_string_list log_destinations = {0};
766
562
            res = loader_parse_json_array_of_strings(inst, log_element, "destinations", &log_destinations);
767
562
            if (res != VK_SUCCESS) {
768
                // is_valid = false;
769
542
            }
770
562
            free_string_list(inst, &log_destinations);
771
562
            struct loader_string_list log_filters = {0};
772
562
            res = loader_parse_json_array_of_strings(inst, log_element, "filters", &log_filters);
773
562
            if (res != VK_SUCCESS) {
774
                // is_valid = false;
775
374
            }
776
562
            free_string_list(inst, &log_filters);
777
562
        }
778
38
    }
779
780
1.82k
    VkResult layer_configurations_res = parse_layer_configurations(inst, settings_to_use, loader_settings);
781
1.82k
    if (VK_ERROR_OUT_OF_HOST_MEMORY == layer_configurations_res) {
782
0
        res = layer_configurations_res;
783
0
        goto out;
784
0
    }
785
786
    // Determine if there exists a layer configuration indicating where to put layers not contained in the settings file
787
    // LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION
788
19.8k
    for (uint32_t i = 0; i < loader_settings->layer_configuration_count; i++) {
789
18.8k
        if (loader_settings->layer_configurations[i].control == LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION) {
790
842
            loader_settings->has_unordered_layer_location = true;
791
842
            break;
792
842
        }
793
18.8k
    }
794
795
1.82k
    VkResult additional_drivers_res = parse_additional_drivers(inst, settings_to_use, loader_settings);
796
1.82k
    if (VK_ERROR_OUT_OF_HOST_MEMORY == additional_drivers_res) {
797
0
        res = additional_drivers_res;
798
0
        goto out;
799
0
    }
800
801
1.82k
    VkResult device_configurations_res = parse_device_configurations(inst, settings_to_use, loader_settings);
802
1.82k
    if (VK_ERROR_OUT_OF_HOST_MEMORY == device_configurations_res) {
803
0
        res = device_configurations_res;
804
0
        goto out;
805
0
    }
806
807
    // Only consider the settings active if there is at least one "setting" active.
808
    // Those are either logging, layers, additional_drivers, or device_configurations.
809
1.82k
    if (loader_settings->debug_level != 0 || loader_settings->layer_configuration_count != 0 ||
810
1.82k
        loader_settings->additional_driver_count != 0 || loader_settings->device_configuration_count != 0) {
811
1.15k
        loader_settings->settings_file_path = settings_file_path;
812
1.15k
        settings_file_path = NULL;
813
1.15k
        loader_settings->settings_active = true;
814
1.15k
    } else {
815
672
        loader_log(inst, VULKAN_LOADER_INFO_BIT, 0,
816
672
                   "vk_loader_settings.json file found at \"%s\" but did not contain any valid settings.", settings_file_path);
817
672
    }
818
7.50k
out:
819
7.50k
    if (NULL != json) {
820
6.99k
        loader_cJSON_Delete(json);
821
6.99k
    }
822
823
7.50k
    loader_instance_heap_free(inst, settings_file_path);
824
825
7.50k
    loader_instance_heap_free(inst, file_format_version_string);
826
7.50k
    return res;
827
1.82k
}
828
829
0
TEST_FUNCTION_EXPORT VkResult update_global_loader_settings(void) {
830
0
    loader_settings settings = {0};
831
0
    VkResult res = get_loader_settings(NULL, &settings);
832
0
    loader_platform_thread_lock_mutex(&global_loader_settings_lock);
833
834
0
    free_loader_settings(NULL, &global_loader_settings);
835
0
    if (res == VK_SUCCESS) {
836
0
        if (!check_if_settings_are_equal(&settings, &global_loader_settings)) {
837
0
            log_settings(NULL, &settings);
838
0
        }
839
840
0
        memcpy(&global_loader_settings, &settings, sizeof(loader_settings));
841
0
        if (global_loader_settings.settings_active && global_loader_settings.debug_level > 0) {
842
0
            loader_set_global_debug_level(global_loader_settings.debug_level);
843
0
        }
844
0
    }
845
0
    loader_platform_thread_unlock_mutex(&global_loader_settings_lock);
846
0
    return res;
847
0
}
848
849
2
void init_global_loader_settings(void) {
850
2
    loader_platform_thread_create_mutex(&global_loader_settings_lock);
851
    // Free out the global settings in case the process was loaded & unloaded
852
2
    free_loader_settings(NULL, &global_loader_settings);
853
2
}
854
0
void teardown_global_loader_settings(void) {
855
0
    free_loader_settings(NULL, &global_loader_settings);
856
0
    loader_platform_thread_delete_mutex(&global_loader_settings_lock);
857
0
}
858
859
0
bool should_skip_logging_global_messages(VkFlags msg_type) {
860
0
    loader_platform_thread_lock_mutex(&global_loader_settings_lock);
861
0
    bool should_skip = global_loader_settings.settings_active && 0 != (msg_type & global_loader_settings.debug_level);
862
0
    loader_platform_thread_unlock_mutex(&global_loader_settings_lock);
863
0
    return should_skip;
864
0
}
865
866
// Use this function to get the correct settings to use based on the context
867
// If inst is NULL - use the global settings and lock the mutex
868
// Else return the settings local to the instance - but do nto lock the mutex
869
10.9k
const loader_settings* get_current_settings_and_lock(const struct loader_instance* inst) {
870
10.9k
    if (inst) {
871
10.9k
        return &inst->settings;
872
10.9k
    }
873
0
    loader_platform_thread_lock_mutex(&global_loader_settings_lock);
874
0
    return &global_loader_settings;
875
10.9k
}
876
// Release the global settings lock if we are using the global settings - aka if inst is NULL
877
10.9k
void release_current_settings_lock(const struct loader_instance* inst) {
878
10.9k
    if (inst == NULL) {
879
0
        loader_platform_thread_unlock_mutex(&global_loader_settings_lock);
880
0
    }
881
10.9k
}
882
883
TEST_FUNCTION_EXPORT VkResult get_settings_layers(const struct loader_instance* inst, struct loader_layer_list* settings_layers,
884
7.50k
                                                  bool* should_search_for_other_layers) {
885
7.50k
    VkResult res = VK_SUCCESS;
886
7.50k
    *should_search_for_other_layers = true;  // default to true
887
888
7.50k
    const loader_settings* settings = get_current_settings_and_lock(inst);
889
890
7.50k
    if (NULL == settings || !settings->settings_active) {
891
6.35k
        goto out;
892
6.35k
    }
893
894
    // Assume the list doesn't contain LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION at first
895
1.15k
    *should_search_for_other_layers = false;
896
897
31.1k
    for (uint32_t i = 0; i < settings->layer_configuration_count; i++) {
898
30.0k
        loader_settings_layer_configuration* layer_config = &settings->layer_configurations[i];
899
900
        // If we encountered a layer that should be forced off, we add it to the settings_layers list but only
901
        // with the data required to compare it with layers not in the settings file (aka name and manifest path)
902
30.0k
        if (layer_config->control == LOADER_SETTINGS_LAYER_CONTROL_OFF) {
903
15.8k
            struct loader_layer_properties props = {0};
904
15.8k
            props.settings_control_value = LOADER_SETTINGS_LAYER_CONTROL_OFF;
905
15.8k
            loader_strncpy(props.info.layerName, VK_MAX_EXTENSION_NAME_SIZE, layer_config->name, VK_MAX_EXTENSION_NAME_SIZE);
906
15.8k
            props.info.layerName[VK_MAX_EXTENSION_NAME_SIZE - 1] = '\0';
907
15.8k
            res = loader_copy_to_new_str(inst, layer_config->path, &props.manifest_file_name);
908
15.8k
            if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
909
0
                goto out;
910
0
            }
911
15.8k
            res = loader_append_layer_property(inst, settings_layers, &props);
912
15.8k
            if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
913
0
                loader_free_layer_properties(inst, &props);
914
0
                goto out;
915
0
            }
916
15.8k
            continue;
917
15.8k
        }
918
919
        // The special layer location that indicates where unordered layers should go only should have the
920
        // settings_control_value set - everything else should be NULL
921
14.1k
        if (layer_config->control == LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION) {
922
11.8k
            struct loader_layer_properties props = {0};
923
11.8k
            props.settings_control_value = LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION;
924
11.8k
            res = loader_append_layer_property(inst, settings_layers, &props);
925
11.8k
            if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
926
0
                loader_free_layer_properties(inst, &props);
927
0
                goto out;
928
0
            }
929
11.8k
            *should_search_for_other_layers = true;
930
11.8k
            continue;
931
11.8k
        }
932
933
2.32k
        if (layer_config->path == NULL) {
934
0
            continue;
935
0
        }
936
937
2.32k
        cJSON* json = NULL;
938
2.32k
        VkResult local_res = loader_get_json(inst, layer_config->path, &json);
939
2.32k
        if (VK_ERROR_OUT_OF_HOST_MEMORY == local_res) {
940
0
            res = VK_ERROR_OUT_OF_HOST_MEMORY;
941
0
            goto out;
942
2.32k
        } else if (VK_SUCCESS != local_res || NULL == json) {
943
2.25k
            continue;
944
2.25k
        }
945
946
        // Makes it possible to know if a new layer was added or not, since the only return value is VkResult
947
73
        size_t count_before_adding = settings_layers->count;
948
949
73
        local_res =
950
73
            loader_add_layer_properties(inst, settings_layers, json, layer_config->treat_as_implicit_manifest, layer_config->path);
951
73
        loader_cJSON_Delete(json);
952
953
        // If the error is anything other than out of memory we still want to try to load the other layers
954
73
        if (VK_ERROR_OUT_OF_HOST_MEMORY == local_res) {
955
0
            res = VK_ERROR_OUT_OF_HOST_MEMORY;
956
0
            goto out;
957
73
        } else if (local_res != VK_SUCCESS || count_before_adding == settings_layers->count) {
958
            // Indicates something was wrong with the layer, can't add it to the list
959
54
            continue;
960
54
        }
961
962
19
        struct loader_layer_properties* newly_added_layer = &settings_layers->list[settings_layers->count - 1];
963
19
        newly_added_layer->settings_control_value = layer_config->control;
964
        // If the manifest file found has a name that differs from the one in the settings, remove this layer from
965
        // consideration
966
19
        bool should_remove = false;
967
19
        if (strncmp(newly_added_layer->info.layerName, layer_config->name, VK_MAX_EXTENSION_NAME_SIZE) != 0) {
968
13
            should_remove = true;
969
13
            loader_remove_layer_in_list(inst, settings_layers, settings_layers->count - 1);
970
13
        }
971
        // Make sure the layer isn't already in the list
972
1.67k
        for (uint32_t j = 0; settings_layers->count > 0 && j < settings_layers->count - 1; j++) {
973
1.65k
            if (0 ==
974
1.65k
                strncmp(settings_layers->list[j].info.layerName, newly_added_layer->info.layerName, VK_MAX_EXTENSION_NAME_SIZE)) {
975
25
                if (0 == (newly_added_layer->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER) &&
976
25
                    strcmp(settings_layers->list[j].lib_name, newly_added_layer->lib_name) == 0) {
977
0
                    should_remove = true;
978
0
                    break;
979
0
                }
980
25
            }
981
1.65k
        }
982
19
        if (should_remove) {
983
13
            loader_remove_layer_in_list(inst, settings_layers, settings_layers->count - 1);
984
13
        }
985
19
    }
986
987
7.50k
out:
988
7.50k
    release_current_settings_lock(inst);
989
7.50k
    return res;
990
1.15k
}
991
992
// Check if layers has an element with the same name.
993
// LAYER_CONTROL_OFF layers are missing some fields, just make sure the layerName is the same
994
// If layer_property is a meta layer, just make sure the layerName is the same
995
// Skip comparing to UNORDERED_LAYER_LOCATION
996
// If layer_property is a regular layer, check if the lib_path is the same.
997
// Make sure that the lib_name pointers are non-null before calling strcmp.
998
353k
bool check_if_layer_is_in_list(struct loader_layer_list* layer_list, struct loader_layer_properties* layer_property) {
999
    // If the layer is a meta layer, just check against the name
1000
559M
    for (uint32_t i = 0; i < layer_list->count; i++) {
1001
558M
        if (0 == strncmp(layer_list->list[i].info.layerName, layer_property->info.layerName, VK_MAX_EXTENSION_NAME_SIZE)) {
1002
488M
            if (layer_list->list[i].settings_control_value == LOADER_SETTINGS_LAYER_CONTROL_OFF) {
1003
2.18k
                return true;
1004
2.18k
            }
1005
488M
            if (VK_LAYER_TYPE_FLAG_META_LAYER == (layer_property->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) {
1006
1.04k
                return true;
1007
1.04k
            }
1008
488M
            if (layer_list->list[i].lib_name && layer_property->lib_name) {
1009
721
                return strcmp(layer_list->list[i].lib_name, layer_property->lib_name) == 0;
1010
721
            }
1011
488M
        }
1012
558M
    }
1013
349k
    return false;
1014
353k
}
1015
1016
VkResult combine_settings_layers_with_regular_layers(const struct loader_instance* inst, struct loader_layer_list* settings_layers,
1017
                                                     struct loader_layer_list* regular_layers,
1018
7.19k
                                                     struct loader_layer_list* output_layers) {
1019
7.19k
    VkResult res = VK_SUCCESS;
1020
7.19k
    bool has_unordered_layer_location = false;
1021
7.19k
    uint32_t unordered_layer_location_index = 0;
1022
    // Location to put layers that aren't known to the settings file
1023
    // Find it here so we dont have to pass in a loader_settings struct
1024
9.55k
    for (uint32_t i = 0; i < settings_layers->count; i++) {
1025
3.19k
        if (settings_layers->list[i].settings_control_value == LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION) {
1026
842
            has_unordered_layer_location = true;
1027
842
            unordered_layer_location_index = i;
1028
842
            break;
1029
842
        }
1030
3.19k
    }
1031
1032
7.19k
    if (settings_layers->count == 0 && regular_layers->count == 0) {
1033
        // No layers to combine
1034
2.63k
        goto out;
1035
4.56k
    } else if (settings_layers->count == 0) {
1036
        // No settings layers - just copy regular to output_layers - memset regular layers to prevent double frees
1037
3.71k
        *output_layers = *regular_layers;
1038
3.71k
        memset(regular_layers, 0, sizeof(struct loader_layer_list));
1039
3.71k
        goto out;
1040
3.71k
    } else if (regular_layers->count == 0 || !has_unordered_layer_location) {
1041
        // No regular layers or has_unordered_layer_location is false - just copy settings to output_layers -
1042
        // memset settings layers to prevent double frees
1043
25
        *output_layers = *settings_layers;
1044
25
        memset(settings_layers, 0, sizeof(struct loader_layer_list));
1045
25
        goto out;
1046
25
    }
1047
1048
817
    res = loader_init_generic_list(inst, (struct loader_generic_list*)output_layers,
1049
817
                                   (settings_layers->count + regular_layers->count) * sizeof(struct loader_layer_properties));
1050
817
    if (VK_SUCCESS != res) {
1051
0
        goto out;
1052
0
    }
1053
1054
    // Insert the settings layers into output_layers up to unordered_layer_index
1055
3.15k
    for (uint32_t i = 0; i < unordered_layer_location_index; i++) {
1056
2.33k
        if (!check_if_layer_is_in_list(output_layers, &settings_layers->list[i])) {
1057
564
            res = loader_append_layer_property(inst, output_layers, &settings_layers->list[i]);
1058
564
            if (VK_SUCCESS != res) {
1059
0
                goto out;
1060
0
            }
1061
564
        }
1062
2.33k
    }
1063
1064
177k
    for (uint32_t i = 0; i < regular_layers->count; i++) {
1065
        // Check if its already been put in the output_layers list as well as the remaining settings_layers
1066
176k
        bool regular_layer_is_ordered = check_if_layer_is_in_list(output_layers, &regular_layers->list[i]) ||
1067
176k
                                        check_if_layer_is_in_list(settings_layers, &regular_layers->list[i]);
1068
        // If it isn't found, add it
1069
176k
        if (!regular_layer_is_ordered) {
1070
174k
            res = loader_append_layer_property(inst, output_layers, &regular_layers->list[i]);
1071
174k
            if (VK_SUCCESS != res) {
1072
0
                goto out;
1073
0
            }
1074
174k
        } else {
1075
            // layer is already ordered and can be safely freed
1076
1.82k
            loader_free_layer_properties(inst, &regular_layers->list[i]);
1077
1.82k
        }
1078
176k
    }
1079
1080
    // Insert the rest of the settings layers into combined_layers from  unordered_layer_index to the end
1081
    // start at one after the unordered_layer_index
1082
1.63k
    for (uint32_t i = unordered_layer_location_index + 1; i < settings_layers->count; i++) {
1083
815
        res = loader_append_layer_property(inst, output_layers, &settings_layers->list[i]);
1084
815
        if (VK_SUCCESS != res) {
1085
0
            goto out;
1086
0
        }
1087
815
    }
1088
1089
7.19k
out:
1090
7.19k
    if (res != VK_SUCCESS) {
1091
0
        loader_delete_layer_list_and_properties(inst, output_layers);
1092
0
    }
1093
1094
7.19k
    return res;
1095
817
}
1096
1097
VkResult enable_correct_layers_from_settings(const struct loader_instance* inst, const struct loader_envvar_all_filters* filters,
1098
                                             uint32_t app_enabled_name_count, const char* const* app_enabled_names,
1099
                                             const struct loader_layer_list* instance_layers,
1100
                                             struct loader_pointer_layer_list* target_layer_list,
1101
0
                                             struct loader_pointer_layer_list* activated_layer_list) {
1102
0
    VkResult res = VK_SUCCESS;
1103
0
    char* vk_instance_layers_env = loader_getenv(ENABLED_LAYERS_ENV, inst);
1104
0
    size_t vk_instance_layers_env_len = 0;
1105
0
    char* vk_instance_layers_env_copy = NULL;
1106
0
    if (vk_instance_layers_env != NULL) {
1107
0
        vk_instance_layers_env_len = strlen(vk_instance_layers_env) + 1;
1108
0
        vk_instance_layers_env_copy = loader_stack_alloc(vk_instance_layers_env_len);
1109
0
        memset(vk_instance_layers_env_copy, 0, vk_instance_layers_env_len);
1110
1111
0
        loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0, "env var \'%s\' defined and adding layers: %s",
1112
0
                   ENABLED_LAYERS_ENV, vk_instance_layers_env);
1113
0
    }
1114
0
    for (uint32_t i = 0; i < instance_layers->count; i++) {
1115
0
        bool enable_layer = false;
1116
0
        struct loader_layer_properties* props = &instance_layers->list[i];
1117
1118
        // Skip the sentinel unordered layer location
1119
0
        if (props->settings_control_value == LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION) {
1120
0
            continue;
1121
0
        }
1122
1123
        // Do not enable the layer if the settings have it set as off
1124
0
        if (props->settings_control_value == LOADER_SETTINGS_LAYER_CONTROL_OFF) {
1125
0
            continue;
1126
0
        }
1127
        // Force enable it based on settings
1128
0
        if (props->settings_control_value == LOADER_SETTINGS_LAYER_CONTROL_ON) {
1129
0
            enable_layer = true;
1130
0
            props->enabled_by_what = ENABLED_BY_WHAT_LOADER_SETTINGS_FILE;
1131
0
        } else {
1132
            // Check if disable filter needs to skip the layer
1133
0
            if ((filters->disable_filter.disable_all || filters->disable_filter.disable_all_implicit ||
1134
0
                 check_name_matches_filter_environment_var(props->info.layerName, &filters->disable_filter.additional_filters)) &&
1135
0
                !check_name_matches_filter_environment_var(props->info.layerName, &filters->allow_filter)) {
1136
                // Report a message that we've forced off a layer if it would have been enabled normally.
1137
0
                loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
1138
0
                           "Layer \"%s\" forced disabled because name matches filter of env var \'%s\'.", props->info.layerName,
1139
0
                           VK_LAYERS_DISABLE_ENV_VAR);
1140
1141
0
                continue;
1142
0
            }
1143
0
        }
1144
        // Check the enable filter
1145
0
        if (!enable_layer && check_name_matches_filter_environment_var(props->info.layerName, &filters->enable_filter)) {
1146
0
            enable_layer = true;
1147
0
            props->enabled_by_what = ENABLED_BY_WHAT_VK_LOADER_LAYERS_ENABLE;
1148
0
            loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
1149
0
                       "Layer \"%s\" forced enabled due to env var \'%s\'.", props->info.layerName, VK_LAYERS_ENABLE_ENV_VAR);
1150
0
        }
1151
1152
        // First look for the old-fashion layers forced on with VK_INSTANCE_LAYERS
1153
0
        if (!enable_layer && vk_instance_layers_env && vk_instance_layers_env_copy && vk_instance_layers_env_len > 0) {
1154
            // Copy the env-var on each iteration, so that loader_get_next_path can correctly find the separators
1155
            // This solution only needs one stack allocation ahead of time rather than an allocation per layer in the
1156
            // env-var
1157
0
            loader_strncpy(vk_instance_layers_env_copy, vk_instance_layers_env_len, vk_instance_layers_env,
1158
0
                           vk_instance_layers_env_len);
1159
1160
0
            char* instance_layers_env_iter = vk_instance_layers_env_copy;
1161
0
            while (instance_layers_env_iter && *instance_layers_env_iter) {
1162
0
                char* next = loader_get_next_path(instance_layers_env_iter);
1163
0
                if (0 == strcmp(instance_layers_env_iter, props->info.layerName)) {
1164
0
                    enable_layer = true;
1165
0
                    props->enabled_by_what = ENABLED_BY_WHAT_VK_INSTANCE_LAYERS;
1166
0
                    break;
1167
0
                }
1168
0
                instance_layers_env_iter = next;
1169
0
            }
1170
0
        }
1171
1172
        // Check if it should be enabled by the application
1173
0
        if (!enable_layer) {
1174
0
            for (uint32_t j = 0; j < app_enabled_name_count; j++) {
1175
0
                if (strcmp(props->info.layerName, app_enabled_names[j]) == 0) {
1176
0
                    enable_layer = true;
1177
0
                    props->enabled_by_what = ENABLED_BY_WHAT_IN_APPLICATION_API;
1178
0
                    break;
1179
0
                }
1180
0
            }
1181
0
        }
1182
1183
        // Check if its an implicit layers and thus enabled by default
1184
0
        if (!enable_layer && (0 == (props->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER)) &&
1185
0
            loader_implicit_layer_is_enabled(inst, filters, props)) {
1186
0
            enable_layer = true;
1187
0
            props->enabled_by_what = ENABLED_BY_WHAT_IMPLICIT_LAYER;
1188
0
        }
1189
1190
0
        if (enable_layer) {
1191
            // Check if the layer is a meta layer reuse the existing function to add the meta layer
1192
0
            if (props->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER) {
1193
0
                res = loader_add_meta_layer(inst, filters, props, target_layer_list, activated_layer_list, instance_layers, NULL);
1194
0
                if (res == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
1195
0
            } else {
1196
0
                res = loader_add_layer_properties_to_list(inst, target_layer_list, props);
1197
0
                if (res != VK_SUCCESS) {
1198
0
                    goto out;
1199
0
                }
1200
0
                res = loader_add_layer_properties_to_list(inst, activated_layer_list, props);
1201
0
                if (res != VK_SUCCESS) {
1202
0
                    goto out;
1203
0
                }
1204
0
            }
1205
0
        }
1206
0
    }
1207
0
out:
1208
0
    return res;
1209
0
}
1210
1211
1.13k
VkResult loader_settings_get_additional_driver_files(const struct loader_instance* inst, struct loader_string_list* out_files) {
1212
1.13k
    VkResult res = VK_SUCCESS;
1213
1214
1.13k
    const loader_settings* settings = get_current_settings_and_lock(inst);
1215
1216
1.13k
    if (NULL == settings || !settings->settings_active) {
1217
1.11k
        goto out;
1218
1.11k
    }
1219
1220
20
    if (settings->additional_drivers_use_exclusively) {
1221
0
        free_string_list(inst, out_files);
1222
0
    }
1223
1224
20
    for (uint32_t i = 0; i < settings->additional_driver_count; i++) {
1225
0
        res = prepend_if_manifest_file(inst, settings->additional_drivers[i].path, out_files);
1226
0
    }
1227
1228
1.13k
out:
1229
1.13k
    release_current_settings_lock(inst);
1230
1.13k
    return res;
1231
20
}
1232
1233
2.26k
bool loader_settings_should_use_driver_environment_variables(const struct loader_instance* inst) {
1234
2.26k
    bool should_use = true;
1235
2.26k
    const loader_settings* settings = get_current_settings_and_lock(inst);
1236
2.26k
    if (NULL == settings || !settings->settings_active) {
1237
2.22k
        goto out;
1238
2.22k
    }
1239
40
    if (settings->device_configuration_count > 0) {
1240
0
        should_use = false;
1241
0
    }
1242
2.26k
out:
1243
2.26k
    release_current_settings_lock(inst);
1244
2.26k
    return should_use;
1245
40
}