Coverage Report

Created: 2026-10-16 06:58

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