Coverage Report

Created: 2025-07-11 06:48

/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
0
void free_layer_configuration(const struct loader_instance* inst, loader_settings_layer_configuration* layer_configuration) {
42
0
    loader_instance_heap_free(inst, layer_configuration->name);
43
0
    loader_instance_heap_free(inst, layer_configuration->path);
44
0
    memset(layer_configuration, 0, sizeof(loader_settings_layer_configuration));
45
0
}
46
47
2
void free_loader_settings(const struct loader_instance* inst, loader_settings* settings) {
48
2
    if (NULL != settings->layer_configurations) {
49
0
        for (uint32_t i = 0; i < settings->layer_configuration_count; i++) {
50
0
            free_layer_configuration(inst, &settings->layer_configurations[i]);
51
0
        }
52
0
    }
53
2
    loader_instance_heap_free(inst, settings->layer_configurations);
54
2
    loader_instance_heap_free(inst, settings->settings_file_path);
55
2
    memset(settings, 0, sizeof(loader_settings));
56
2
}
57
58
0
loader_settings_layer_control parse_control_string(char* control_string) {
59
0
    loader_settings_layer_control layer_control = LOADER_SETTINGS_LAYER_CONTROL_DEFAULT;
60
0
    if (strcmp(control_string, "auto") == 0)
61
0
        layer_control = LOADER_SETTINGS_LAYER_CONTROL_DEFAULT;
62
0
    else if (strcmp(control_string, "on") == 0)
63
0
        layer_control = LOADER_SETTINGS_LAYER_CONTROL_ON;
64
0
    else if (strcmp(control_string, "off") == 0)
65
0
        layer_control = LOADER_SETTINGS_LAYER_CONTROL_OFF;
66
0
    else if (strcmp(control_string, "unordered_layer_location") == 0)
67
0
        layer_control = LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION;
68
0
    return layer_control;
69
0
}
70
71
0
const char* loader_settings_layer_control_to_string(loader_settings_layer_control control) {
72
0
    switch (control) {
73
0
        case (LOADER_SETTINGS_LAYER_CONTROL_DEFAULT):
74
0
            return "auto";
75
0
        case (LOADER_SETTINGS_LAYER_CONTROL_ON):
76
0
            return "on";
77
0
        case (LOADER_SETTINGS_LAYER_CONTROL_OFF):
78
0
            return "off";
79
0
        case (LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION):
80
0
            return "unordered_layer_location";
81
0
        default:
82
0
            return "UNKNOWN_LAYER_CONTROl";
83
0
    }
84
0
}
85
86
0
uint32_t parse_log_filters_from_strings(struct loader_string_list* log_filters) {
87
0
    uint32_t filters = 0;
88
0
    for (uint32_t i = 0; i < log_filters->count; i++) {
89
0
        if (strcmp(log_filters->list[i], "all") == 0)
90
0
            filters |= VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_PERF_BIT | VULKAN_LOADER_ERROR_BIT |
91
0
                       VULKAN_LOADER_DEBUG_BIT | VULKAN_LOADER_LAYER_BIT | VULKAN_LOADER_DRIVER_BIT | VULKAN_LOADER_VALIDATION_BIT;
92
0
        else if (strcmp(log_filters->list[i], "info") == 0)
93
0
            filters |= VULKAN_LOADER_INFO_BIT;
94
0
        else if (strcmp(log_filters->list[i], "warn") == 0)
95
0
            filters |= VULKAN_LOADER_WARN_BIT;
96
0
        else if (strcmp(log_filters->list[i], "perf") == 0)
97
0
            filters |= VULKAN_LOADER_PERF_BIT;
98
0
        else if (strcmp(log_filters->list[i], "error") == 0)
99
0
            filters |= VULKAN_LOADER_ERROR_BIT;
100
0
        else if (strcmp(log_filters->list[i], "debug") == 0)
101
0
            filters |= VULKAN_LOADER_DEBUG_BIT;
102
0
        else if (strcmp(log_filters->list[i], "layer") == 0)
103
0
            filters |= VULKAN_LOADER_LAYER_BIT;
104
0
        else if (strcmp(log_filters->list[i], "driver") == 0)
105
0
            filters |= VULKAN_LOADER_DRIVER_BIT;
106
0
        else if (strcmp(log_filters->list[i], "validation") == 0)
107
0
            filters |= VULKAN_LOADER_VALIDATION_BIT;
108
0
    }
109
0
    return filters;
110
0
}
111
112
0
bool parse_json_enable_disable_option(cJSON* object) {
113
0
    char* str = loader_cJSON_GetStringValue(object);
114
0
    if (NULL == str) {
115
0
        return false;
116
0
    }
117
0
    bool enable = false;
118
0
    if (strcmp(str, "enabled") == 0) {
119
0
        enable = true;
120
0
    }
121
0
    return enable;
122
0
}
123
124
VkResult parse_layer_configuration(const struct loader_instance* inst, cJSON* layer_configuration_json,
125
0
                                   loader_settings_layer_configuration* layer_configuration) {
126
0
    char* control_string = NULL;
127
0
    VkResult res = loader_parse_json_string(layer_configuration_json, "control", &control_string);
128
0
    if (res != VK_SUCCESS) {
129
0
        goto out;
130
0
    }
131
0
    layer_configuration->control = parse_control_string(control_string);
132
0
    loader_instance_heap_free(inst, control_string);
133
134
    // If that is the only value - do no further parsing
135
0
    if (layer_configuration->control == LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION) {
136
0
        goto out;
137
0
    }
138
139
0
    res = loader_parse_json_string(layer_configuration_json, "name", &(layer_configuration->name));
140
0
    if (res != VK_SUCCESS) {
141
0
        goto out;
142
0
    }
143
144
0
    res = loader_parse_json_string(layer_configuration_json, "path", &(layer_configuration->path));
145
0
    if (res != VK_SUCCESS) {
146
0
        goto out;
147
0
    }
148
149
0
    cJSON* treat_as_implicit_manifest = loader_cJSON_GetObjectItem(layer_configuration_json, "treat_as_implicit_manifest");
150
0
    if (treat_as_implicit_manifest && treat_as_implicit_manifest->type == cJSON_True) {
151
0
        layer_configuration->treat_as_implicit_manifest = true;
152
0
    }
153
0
out:
154
0
    if (VK_SUCCESS != res) {
155
0
        free_layer_configuration(inst, layer_configuration);
156
0
    }
157
0
    return res;
158
0
}
159
160
0
VkResult parse_layer_configurations(const struct loader_instance* inst, cJSON* settings_object, loader_settings* loader_settings) {
161
0
    VkResult res = VK_SUCCESS;
162
163
0
    cJSON* layer_configurations = loader_cJSON_GetObjectItem(settings_object, "layers");
164
    // If the layers object isn't present, return early with success to allow the settings file to still apply
165
0
    if (NULL == layer_configurations) {
166
0
        return VK_SUCCESS;
167
0
    }
168
169
0
    uint32_t layer_configurations_count = loader_cJSON_GetArraySize(layer_configurations);
170
0
    if (layer_configurations_count == 0) {
171
0
        return VK_SUCCESS;
172
0
    }
173
174
0
    loader_settings->layer_configuration_count = layer_configurations_count;
175
176
0
    loader_settings->layer_configurations = loader_instance_heap_calloc(
177
0
        inst, sizeof(loader_settings_layer_configuration) * layer_configurations_count, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
178
0
    if (NULL == loader_settings->layer_configurations) {
179
0
        res = VK_ERROR_OUT_OF_HOST_MEMORY;
180
0
        goto out;
181
0
    }
182
183
0
    cJSON* layer = NULL;
184
0
    size_t i = 0;
185
0
    cJSON_ArrayForEach(layer, layer_configurations) {
186
0
        if (layer->type != cJSON_Object) {
187
0
            res = VK_ERROR_INITIALIZATION_FAILED;
188
0
            goto out;
189
0
        }
190
0
        res = parse_layer_configuration(inst, layer, &(loader_settings->layer_configurations[i++]));
191
0
        if (VK_SUCCESS != res) {
192
0
            goto out;
193
0
        }
194
0
    }
195
0
out:
196
0
    if (res != VK_SUCCESS) {
197
0
        if (loader_settings->layer_configurations) {
198
0
            for (size_t index = 0; index < loader_settings->layer_configuration_count; index++) {
199
0
                free_layer_configuration(inst, &(loader_settings->layer_configurations[index]));
200
0
            }
201
0
            loader_settings->layer_configuration_count = 0;
202
0
            loader_instance_heap_free(inst, loader_settings->layer_configurations);
203
0
            loader_settings->layer_configurations = NULL;
204
0
        }
205
0
    }
206
207
0
    return res;
208
0
}
209
210
VkResult check_if_settings_path_exists(const struct loader_instance* inst, const char* base, const char* suffix,
211
0
                                       char** settings_file_path) {
212
0
    if (NULL == base || NULL == suffix) {
213
0
        return VK_ERROR_INITIALIZATION_FAILED;
214
0
    }
215
0
    size_t base_len = strlen(base);
216
0
    size_t suffix_len = strlen(suffix);
217
0
    size_t path_len = base_len + suffix_len + 1;
218
0
    *settings_file_path = loader_instance_heap_calloc(inst, path_len, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
219
0
    if (NULL == *settings_file_path) {
220
0
        return VK_ERROR_OUT_OF_HOST_MEMORY;
221
0
    }
222
0
    loader_strncpy(*settings_file_path, path_len, base, base_len);
223
0
    loader_strncat(*settings_file_path, path_len, suffix, suffix_len);
224
225
0
    if (!loader_platform_file_exists(*settings_file_path)) {
226
0
        loader_instance_heap_free(inst, *settings_file_path);
227
0
        *settings_file_path = NULL;
228
0
        return VK_ERROR_INITIALIZATION_FAILED;
229
0
    }
230
0
    return VK_SUCCESS;
231
0
}
232
0
VkResult get_unix_settings_path(const struct loader_instance* inst, char** settings_file_path) {
233
0
    VkResult res =
234
0
        check_if_settings_path_exists(inst, loader_secure_getenv("HOME", inst),
235
0
                                      "/.local/share/vulkan/loader_settings.d/" VK_LOADER_SETTINGS_FILENAME, settings_file_path);
236
0
    if (res == VK_SUCCESS) {
237
0
        return res;
238
0
    }
239
    // If HOME isn't set, fallback to XDG_DATA_HOME
240
0
    res = check_if_settings_path_exists(inst, loader_secure_getenv("XDG_DATA_HOME", inst),
241
0
                                        "/vulkan/loader_settings.d/" VK_LOADER_SETTINGS_FILENAME, settings_file_path);
242
0
    if (res == VK_SUCCESS) {
243
0
        return res;
244
0
    }
245
    // if XDG_DATA_HOME isn't set, fallback to /etc.
246
    // note that the settings_fil_path_suffix stays the same since its the same layout as for XDG_DATA_HOME
247
0
    return check_if_settings_path_exists(inst, "/etc", "/vulkan/loader_settings.d/" VK_LOADER_SETTINGS_FILENAME,
248
0
                                         settings_file_path);
249
0
}
250
251
0
bool check_if_settings_are_equal(loader_settings* a, loader_settings* b) {
252
    // If either pointer is null, return true
253
0
    if (NULL == a || NULL == b) return false;
254
0
    bool are_equal = true;
255
0
    are_equal &= a->settings_active == b->settings_active;
256
0
    are_equal &= a->has_unordered_layer_location == b->has_unordered_layer_location;
257
0
    are_equal &= a->debug_level == b->debug_level;
258
0
    are_equal &= a->layer_configuration_count == b->layer_configuration_count;
259
0
    if (!are_equal) return false;
260
0
    for (uint32_t i = 0; i < a->layer_configuration_count && i < b->layer_configuration_count; i++) {
261
0
        if (a->layer_configurations[i].name && b->layer_configurations[i].name) {
262
0
            are_equal &= 0 == strcmp(a->layer_configurations[i].name, b->layer_configurations[i].name);
263
0
        } else {
264
0
            are_equal = false;
265
0
        }
266
0
        if (a->layer_configurations[i].path && b->layer_configurations[i].path) {
267
0
            are_equal &= 0 == strcmp(a->layer_configurations[i].path, b->layer_configurations[i].path);
268
0
        } else {
269
0
            are_equal = false;
270
0
        }
271
0
        are_equal &= a->layer_configurations[i].control == b->layer_configurations[i].control;
272
0
    }
273
0
    return are_equal;
274
0
}
275
276
0
void log_settings(const struct loader_instance* inst, loader_settings* settings) {
277
0
    if (settings == NULL) {
278
0
        return;
279
0
    }
280
0
    loader_log(inst, VULKAN_LOADER_INFO_BIT, 0, "Using layer configurations found in loader settings from %s",
281
0
               settings->settings_file_path);
282
283
0
    char cmd_line_msg[64] = {0};
284
0
    size_t cmd_line_size = sizeof(cmd_line_msg);
285
286
0
    cmd_line_msg[0] = '\0';
287
288
0
    generate_debug_flag_str(settings->debug_level, cmd_line_size, cmd_line_msg);
289
0
    if (strlen(cmd_line_msg)) {
290
0
        loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "Loader Settings Filters for Logging to Standard Error: %s", cmd_line_msg);
291
0
    }
292
293
0
    loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "Layer Configurations count = %d", settings->layer_configuration_count);
294
0
    for (uint32_t i = 0; i < settings->layer_configuration_count; i++) {
295
0
        loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "---- Layer Configuration [%d] ----", i);
296
0
        if (settings->layer_configurations[i].control != LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION) {
297
0
            loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "Name: %s", settings->layer_configurations[i].name);
298
0
            loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "Path: %s", settings->layer_configurations[i].path);
299
0
            loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "Layer Type: %s",
300
0
                       settings->layer_configurations[i].treat_as_implicit_manifest ? "Implicit" : "Explicit");
301
0
        }
302
0
        loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "Control: %s",
303
0
                   loader_settings_layer_control_to_string(settings->layer_configurations[i].control));
304
0
    }
305
0
    loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "---------------------------------");
306
0
}
307
308
// Loads the vk_loader_settings.json file
309
// Returns VK_SUCCESS if it was found & was successfully parsed. Otherwise, it returns VK_ERROR_INITIALIZATION_FAILED if it
310
// wasn't found or failed to parse, and returns VK_ERROR_OUT_OF_HOST_MEMORY if it was unable to allocate enough memory.
311
0
VkResult get_loader_settings(const struct loader_instance* inst, loader_settings* loader_settings) {
312
0
    VkResult res = VK_SUCCESS;
313
0
    cJSON* json = NULL;
314
0
    char* file_format_version_string = NULL;
315
0
    char* settings_file_path = NULL;
316
#if defined(WIN32)
317
    res = windows_get_loader_settings_file_path(inst, &settings_file_path);
318
    if (res != VK_SUCCESS) {
319
        loader_log(inst, VULKAN_LOADER_INFO_BIT, 0,
320
                   "No valid vk_loader_settings.json file found, no loader settings will be active");
321
        goto out;
322
    }
323
324
#elif COMMON_UNIX_PLATFORMS
325
    res = get_unix_settings_path(inst, &settings_file_path);
326
0
    if (res != VK_SUCCESS) {
327
0
        loader_log(inst, VULKAN_LOADER_INFO_BIT, 0,
328
0
                   "No valid vk_loader_settings.json file found, no loader settings will be active");
329
0
        goto out;
330
0
    }
331
#else
332
#warning "Unsupported platform - must specify platform specific location for vk_loader_settings.json"
333
#endif
334
335
0
    res = loader_get_json(inst, settings_file_path, &json);
336
    // Make sure sure the top level json value is an object
337
0
    if (res != VK_SUCCESS || NULL == json || json->type != cJSON_Object) {
338
0
        goto out;
339
0
    }
340
341
0
    res = loader_parse_json_string(json, "file_format_version", &file_format_version_string);
342
0
    if (res != VK_SUCCESS) {
343
0
        if (res != VK_ERROR_OUT_OF_HOST_MEMORY) {
344
0
            loader_log(
345
0
                inst, VULKAN_LOADER_DEBUG_BIT, 0,
346
0
                "Loader settings file from %s missing required field file_format_version - no loader settings will be active",
347
0
                settings_file_path);
348
0
        }
349
0
        goto out;
350
0
    }
351
352
    // Because the file may contain either a "settings_array" or a single "settings" object, we need to create a cJSON so that we
353
    // can iterate on both cases with common code
354
0
    cJSON settings_iter_parent = {0};
355
356
0
    cJSON* settings_array = loader_cJSON_GetObjectItem(json, "settings_array");
357
0
    cJSON* single_settings_object = loader_cJSON_GetObjectItem(json, "settings");
358
0
    if (NULL != settings_array) {
359
0
        memcpy(&settings_iter_parent, settings_array, sizeof(cJSON));
360
0
    } else if (NULL != single_settings_object) {
361
0
        settings_iter_parent.child = single_settings_object;
362
0
    } else if (settings_array == NULL && single_settings_object) {
363
0
        loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0,
364
0
                   "Loader settings file from %s missing required settings objects: Either one of the \"settings\" or "
365
0
                   "\"settings_array\" objects must be present - no loader settings will be active",
366
0
                   settings_file_path);
367
0
        res = VK_ERROR_INITIALIZATION_FAILED;
368
0
        goto out;
369
0
    }
370
371
    // Corresponds to the settings object that has no app keys
372
0
    cJSON* global_settings = NULL;
373
    // Corresponds to the settings object which has a matching app key
374
0
    cJSON* settings_to_use = NULL;
375
376
0
    char current_process_path[1024];
377
0
    bool valid_exe_path = NULL != loader_platform_executable_path(current_process_path, 1024);
378
379
0
    cJSON* settings_object_iter = NULL;
380
0
    cJSON_ArrayForEach(settings_object_iter, &settings_iter_parent) {
381
0
        if (settings_object_iter->type != cJSON_Object) {
382
0
            loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0,
383
0
                       "Loader settings file from %s has a settings element that is not an object", settings_file_path);
384
0
            break;
385
0
        }
386
387
0
        cJSON* app_keys = loader_cJSON_GetObjectItem(settings_object_iter, "app_keys");
388
0
        if (NULL == app_keys) {
389
            // use the first 'global' settings that has no app keys as the global one
390
0
            if (global_settings == NULL) {
391
0
                global_settings = settings_object_iter;
392
0
            }
393
0
            continue;
394
0
        }
395
        // No sense iterating if we couldn't get the executable path
396
0
        if (!valid_exe_path) {
397
0
            break;
398
0
        }
399
0
        cJSON* app_key = NULL;
400
0
        cJSON_ArrayForEach(app_key, app_keys) {
401
0
            char* app_key_str = loader_cJSON_GetStringValue(app_key);
402
0
            if (app_key_str && strcmp(current_process_path, app_key_str) == 0) {
403
0
                settings_to_use = settings_object_iter;
404
0
                break;
405
0
            }
406
0
        }
407
408
        // Break if we have found a matching current_process_path
409
0
        if (NULL != settings_to_use) {
410
0
            break;
411
0
        }
412
0
    }
413
414
    // No app specific settings match - either use global settings or exit
415
0
    if (settings_to_use == NULL) {
416
0
        if (global_settings == NULL) {
417
0
            loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0,
418
0
                       "Loader settings file from %s missing global settings and none of the app specific settings matched the "
419
0
                       "current application - no loader settings will be active",
420
0
                       settings_file_path);
421
0
            goto out;  // No global settings were found - exit
422
0
        } else {
423
0
            settings_to_use = global_settings;  // Global settings are present - use it
424
0
        }
425
0
    }
426
427
    // optional
428
0
    cJSON* stderr_filter = loader_cJSON_GetObjectItem(settings_to_use, "stderr_log");
429
0
    if (NULL != stderr_filter) {
430
0
        struct loader_string_list stderr_log = {0};
431
0
        res = loader_parse_json_array_of_strings(inst, settings_to_use, "stderr_log", &stderr_log);
432
0
        if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
433
0
            goto out;
434
0
        }
435
0
        loader_settings->debug_level = parse_log_filters_from_strings(&stderr_log);
436
0
        free_string_list(inst, &stderr_log);
437
0
    }
438
439
    // optional
440
0
    cJSON* logs_to_use = loader_cJSON_GetObjectItem(settings_to_use, "log_locations");
441
0
    if (NULL != logs_to_use) {
442
0
        cJSON* log_element = NULL;
443
0
        cJSON_ArrayForEach(log_element, logs_to_use) {
444
            // bool is_valid = true;
445
0
            struct loader_string_list log_destinations = {0};
446
0
            res = loader_parse_json_array_of_strings(inst, log_element, "destinations", &log_destinations);
447
0
            if (res != VK_SUCCESS) {
448
                // is_valid = false;
449
0
            }
450
0
            free_string_list(inst, &log_destinations);
451
0
            struct loader_string_list log_filters = {0};
452
0
            res = loader_parse_json_array_of_strings(inst, log_element, "filters", &log_filters);
453
0
            if (res != VK_SUCCESS) {
454
                // is_valid = false;
455
0
            }
456
0
            free_string_list(inst, &log_filters);
457
0
        }
458
0
    }
459
460
0
    res = parse_layer_configurations(inst, settings_to_use, loader_settings);
461
0
    if (res != VK_SUCCESS) {
462
0
        goto out;
463
0
    }
464
465
    // Determine if there exists a layer configuration indicating where to put layers not contained in the settings file
466
    // LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION
467
0
    for (uint32_t i = 0; i < loader_settings->layer_configuration_count; i++) {
468
0
        if (loader_settings->layer_configurations[i].control == LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION) {
469
0
            loader_settings->has_unordered_layer_location = true;
470
0
            break;
471
0
        }
472
0
    }
473
474
0
    loader_settings->settings_file_path = settings_file_path;
475
0
    settings_file_path = NULL;
476
0
    loader_settings->settings_active = true;
477
0
out:
478
0
    if (NULL != json) {
479
0
        loader_cJSON_Delete(json);
480
0
    }
481
482
0
    loader_instance_heap_free(inst, settings_file_path);
483
484
0
    loader_instance_heap_free(inst, file_format_version_string);
485
0
    return res;
486
0
}
487
488
0
TEST_FUNCTION_EXPORT VkResult update_global_loader_settings(void) {
489
0
    loader_settings settings = {0};
490
0
    VkResult res = get_loader_settings(NULL, &settings);
491
0
    loader_platform_thread_lock_mutex(&global_loader_settings_lock);
492
493
0
    free_loader_settings(NULL, &global_loader_settings);
494
0
    if (res == VK_SUCCESS) {
495
0
        if (!check_if_settings_are_equal(&settings, &global_loader_settings)) {
496
0
            log_settings(NULL, &settings);
497
0
        }
498
499
0
        memcpy(&global_loader_settings, &settings, sizeof(loader_settings));
500
0
        if (global_loader_settings.settings_active && global_loader_settings.debug_level > 0) {
501
0
            loader_set_global_debug_level(global_loader_settings.debug_level);
502
0
        }
503
0
    }
504
0
    loader_platform_thread_unlock_mutex(&global_loader_settings_lock);
505
0
    return res;
506
0
}
507
508
2
void init_global_loader_settings(void) {
509
2
    loader_platform_thread_create_mutex(&global_loader_settings_lock);
510
    // Free out the global settings in case the process was loaded & unloaded
511
2
    free_loader_settings(NULL, &global_loader_settings);
512
2
}
513
0
void teardown_global_loader_settings(void) {
514
0
    free_loader_settings(NULL, &global_loader_settings);
515
0
    loader_platform_thread_delete_mutex(&global_loader_settings_lock);
516
0
}
517
518
0
bool should_skip_logging_global_messages(VkFlags msg_type) {
519
0
    loader_platform_thread_lock_mutex(&global_loader_settings_lock);
520
0
    bool should_skip = global_loader_settings.settings_active && 0 != (msg_type & global_loader_settings.debug_level);
521
0
    loader_platform_thread_unlock_mutex(&global_loader_settings_lock);
522
0
    return should_skip;
523
0
}
524
525
// Use this function to get the correct settings to use based on the context
526
// If inst is NULL - use the global settings and lock the mutex
527
// Else return the settings local to the instance - but do nto lock the mutex
528
0
const loader_settings* get_current_settings_and_lock(const struct loader_instance* inst) {
529
0
    if (inst) {
530
0
        return &inst->settings;
531
0
    }
532
0
    loader_platform_thread_lock_mutex(&global_loader_settings_lock);
533
0
    return &global_loader_settings;
534
0
}
535
// Release the global settings lock if we are using the global settings - aka if inst is NULL
536
0
void release_current_settings_lock(const struct loader_instance* inst) {
537
0
    if (inst == NULL) {
538
0
        loader_platform_thread_unlock_mutex(&global_loader_settings_lock);
539
0
    }
540
0
}
541
542
TEST_FUNCTION_EXPORT VkResult get_settings_layers(const struct loader_instance* inst, struct loader_layer_list* settings_layers,
543
0
                                                  bool* should_search_for_other_layers) {
544
0
    VkResult res = VK_SUCCESS;
545
0
    *should_search_for_other_layers = true;  // default to true
546
547
0
    const loader_settings* settings = get_current_settings_and_lock(inst);
548
549
0
    if (NULL == settings || !settings->settings_active) {
550
0
        goto out;
551
0
    }
552
553
    // Assume the list doesn't contain LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION at first
554
0
    *should_search_for_other_layers = false;
555
556
0
    for (uint32_t i = 0; i < settings->layer_configuration_count; i++) {
557
0
        loader_settings_layer_configuration* layer_config = &settings->layer_configurations[i];
558
559
        // If we encountered a layer that should be forced off, we add it to the settings_layers list but only
560
        // with the data required to compare it with layers not in the settings file (aka name and manifest path)
561
0
        if (layer_config->control == LOADER_SETTINGS_LAYER_CONTROL_OFF) {
562
0
            struct loader_layer_properties props = {0};
563
0
            props.settings_control_value = LOADER_SETTINGS_LAYER_CONTROL_OFF;
564
0
            loader_strncpy(props.info.layerName, VK_MAX_EXTENSION_NAME_SIZE, layer_config->name, VK_MAX_EXTENSION_NAME_SIZE);
565
0
            props.info.layerName[VK_MAX_EXTENSION_NAME_SIZE - 1] = '\0';
566
0
            res = loader_copy_to_new_str(inst, layer_config->path, &props.manifest_file_name);
567
0
            if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
568
0
                goto out;
569
0
            }
570
0
            res = loader_append_layer_property(inst, settings_layers, &props);
571
0
            if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
572
0
                loader_free_layer_properties(inst, &props);
573
0
                goto out;
574
0
            }
575
0
            continue;
576
0
        }
577
578
        // The special layer location that indicates where unordered layers should go only should have the
579
        // settings_control_value set - everything else should be NULL
580
0
        if (layer_config->control == LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION) {
581
0
            struct loader_layer_properties props = {0};
582
0
            props.settings_control_value = LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION;
583
0
            res = loader_append_layer_property(inst, settings_layers, &props);
584
0
            if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
585
0
                loader_free_layer_properties(inst, &props);
586
0
                goto out;
587
0
            }
588
0
            *should_search_for_other_layers = true;
589
0
            continue;
590
0
        }
591
592
0
        if (layer_config->path == NULL) {
593
0
            continue;
594
0
        }
595
596
0
        cJSON* json = NULL;
597
0
        VkResult local_res = loader_get_json(inst, layer_config->path, &json);
598
0
        if (VK_ERROR_OUT_OF_HOST_MEMORY == local_res) {
599
0
            res = VK_ERROR_OUT_OF_HOST_MEMORY;
600
0
            goto out;
601
0
        } else if (VK_SUCCESS != local_res || NULL == json) {
602
0
            continue;
603
0
        }
604
605
        // Makes it possible to know if a new layer was added or not, since the only return value is VkResult
606
0
        size_t count_before_adding = settings_layers->count;
607
608
0
        local_res =
609
0
            loader_add_layer_properties(inst, settings_layers, json, layer_config->treat_as_implicit_manifest, layer_config->path);
610
0
        loader_cJSON_Delete(json);
611
612
        // If the error is anything other than out of memory we still want to try to load the other layers
613
0
        if (VK_ERROR_OUT_OF_HOST_MEMORY == local_res) {
614
0
            res = VK_ERROR_OUT_OF_HOST_MEMORY;
615
0
            goto out;
616
0
        } else if (local_res != VK_SUCCESS || count_before_adding == settings_layers->count) {
617
            // Indicates something was wrong with the layer, can't add it to the list
618
0
            continue;
619
0
        }
620
621
0
        struct loader_layer_properties* newly_added_layer = &settings_layers->list[settings_layers->count - 1];
622
0
        newly_added_layer->settings_control_value = layer_config->control;
623
        // If the manifest file found has a name that differs from the one in the settings, remove this layer from
624
        // consideration
625
0
        bool should_remove = false;
626
0
        if (strncmp(newly_added_layer->info.layerName, layer_config->name, VK_MAX_EXTENSION_NAME_SIZE) != 0) {
627
0
            should_remove = true;
628
0
            loader_remove_layer_in_list(inst, settings_layers, settings_layers->count - 1);
629
0
        }
630
        // Make sure the layer isn't already in the list
631
0
        for (uint32_t j = 0; settings_layers->count > 0 && j < settings_layers->count - 1; j++) {
632
0
            if (0 ==
633
0
                strncmp(settings_layers->list[j].info.layerName, newly_added_layer->info.layerName, VK_MAX_EXTENSION_NAME_SIZE)) {
634
0
                if (0 == (newly_added_layer->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER) &&
635
0
                    strcmp(settings_layers->list[j].lib_name, newly_added_layer->lib_name) == 0) {
636
0
                    should_remove = true;
637
0
                    break;
638
0
                }
639
0
            }
640
0
        }
641
0
        if (should_remove) {
642
0
            loader_remove_layer_in_list(inst, settings_layers, settings_layers->count - 1);
643
0
        }
644
0
    }
645
646
0
out:
647
0
    release_current_settings_lock(inst);
648
0
    return res;
649
0
}
650
651
// Check if layers has an element with the same name.
652
// LAYER_CONTROL_OFF layers are missing some fields, just make sure the layerName is the same
653
// If layer_property is a meta layer, just make sure the layerName is the same
654
// Skip comparing to UNORDERED_LAYER_LOCATION
655
// If layer_property is a regular layer, check if the lib_path is the same.
656
// Make sure that the lib_name pointers are non-null before calling strcmp.
657
0
bool check_if_layer_is_in_list(struct loader_layer_list* layer_list, struct loader_layer_properties* layer_property) {
658
    // If the layer is a meta layer, just check against the name
659
0
    for (uint32_t i = 0; i < layer_list->count; i++) {
660
0
        if (0 == strncmp(layer_list->list[i].info.layerName, layer_property->info.layerName, VK_MAX_EXTENSION_NAME_SIZE)) {
661
0
            if (layer_list->list[i].settings_control_value == LOADER_SETTINGS_LAYER_CONTROL_OFF) {
662
0
                return true;
663
0
            }
664
0
            if (VK_LAYER_TYPE_FLAG_META_LAYER == (layer_property->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) {
665
0
                return true;
666
0
            }
667
0
            if (layer_list->list[i].lib_name && layer_property->lib_name) {
668
0
                return strcmp(layer_list->list[i].lib_name, layer_property->lib_name) == 0;
669
0
            }
670
0
        }
671
0
    }
672
0
    return false;
673
0
}
674
675
VkResult combine_settings_layers_with_regular_layers(const struct loader_instance* inst, struct loader_layer_list* settings_layers,
676
                                                     struct loader_layer_list* regular_layers,
677
0
                                                     struct loader_layer_list* output_layers) {
678
0
    VkResult res = VK_SUCCESS;
679
0
    bool has_unordered_layer_location = false;
680
0
    uint32_t unordered_layer_location_index = 0;
681
    // Location to put layers that aren't known to the settings file
682
    // Find it here so we dont have to pass in a loader_settings struct
683
0
    for (uint32_t i = 0; i < settings_layers->count; i++) {
684
0
        if (settings_layers->list[i].settings_control_value == LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION) {
685
0
            has_unordered_layer_location = true;
686
0
            unordered_layer_location_index = i;
687
0
            break;
688
0
        }
689
0
    }
690
691
0
    if (settings_layers->count == 0 && regular_layers->count == 0) {
692
        // No layers to combine
693
0
        goto out;
694
0
    } else if (settings_layers->count == 0) {
695
        // No settings layers - just copy regular to output_layers - memset regular layers to prevent double frees
696
0
        *output_layers = *regular_layers;
697
0
        memset(regular_layers, 0, sizeof(struct loader_layer_list));
698
0
        goto out;
699
0
    } else if (regular_layers->count == 0 || !has_unordered_layer_location) {
700
        // No regular layers or has_unordered_layer_location is false - just copy settings to output_layers -
701
        // memset settings layers to prevent double frees
702
0
        *output_layers = *settings_layers;
703
0
        memset(settings_layers, 0, sizeof(struct loader_layer_list));
704
0
        goto out;
705
0
    }
706
707
0
    res = loader_init_generic_list(inst, (struct loader_generic_list*)output_layers,
708
0
                                   (settings_layers->count + regular_layers->count) * sizeof(struct loader_layer_properties));
709
0
    if (VK_SUCCESS != res) {
710
0
        goto out;
711
0
    }
712
713
    // Insert the settings layers into output_layers up to unordered_layer_index
714
0
    for (uint32_t i = 0; i < unordered_layer_location_index; i++) {
715
0
        if (!check_if_layer_is_in_list(output_layers, &settings_layers->list[i])) {
716
0
            res = loader_append_layer_property(inst, output_layers, &settings_layers->list[i]);
717
0
            if (VK_SUCCESS != res) {
718
0
                goto out;
719
0
            }
720
0
        }
721
0
    }
722
723
0
    for (uint32_t i = 0; i < regular_layers->count; i++) {
724
        // Check if its already been put in the output_layers list as well as the remaining settings_layers
725
0
        bool regular_layer_is_ordered = check_if_layer_is_in_list(output_layers, &regular_layers->list[i]) ||
726
0
                                        check_if_layer_is_in_list(settings_layers, &regular_layers->list[i]);
727
        // If it isn't found, add it
728
0
        if (!regular_layer_is_ordered) {
729
0
            res = loader_append_layer_property(inst, output_layers, &regular_layers->list[i]);
730
0
            if (VK_SUCCESS != res) {
731
0
                goto out;
732
0
            }
733
0
        } else {
734
            // layer is already ordered and can be safely freed
735
0
            loader_free_layer_properties(inst, &regular_layers->list[i]);
736
0
        }
737
0
    }
738
739
    // Insert the rest of the settings layers into combined_layers from  unordered_layer_index to the end
740
    // start at one after the unordered_layer_index
741
0
    for (uint32_t i = unordered_layer_location_index + 1; i < settings_layers->count; i++) {
742
0
        res = loader_append_layer_property(inst, output_layers, &settings_layers->list[i]);
743
0
        if (VK_SUCCESS != res) {
744
0
            goto out;
745
0
        }
746
0
    }
747
748
0
out:
749
0
    if (res != VK_SUCCESS) {
750
0
        loader_delete_layer_list_and_properties(inst, output_layers);
751
0
    }
752
753
0
    return res;
754
0
}
755
756
VkResult enable_correct_layers_from_settings(const struct loader_instance* inst, const struct loader_envvar_all_filters* filters,
757
                                             uint32_t app_enabled_name_count, const char* const* app_enabled_names,
758
                                             const struct loader_layer_list* instance_layers,
759
                                             struct loader_pointer_layer_list* target_layer_list,
760
0
                                             struct loader_pointer_layer_list* activated_layer_list) {
761
0
    VkResult res = VK_SUCCESS;
762
0
    char* vk_instance_layers_env = loader_getenv(ENABLED_LAYERS_ENV, inst);
763
0
    size_t vk_instance_layers_env_len = 0;
764
0
    char* vk_instance_layers_env_copy = NULL;
765
0
    if (vk_instance_layers_env != NULL) {
766
0
        vk_instance_layers_env_len = strlen(vk_instance_layers_env) + 1;
767
0
        vk_instance_layers_env_copy = loader_stack_alloc(vk_instance_layers_env_len);
768
0
        memset(vk_instance_layers_env_copy, 0, vk_instance_layers_env_len);
769
770
0
        loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0, "env var \'%s\' defined and adding layers: %s",
771
0
                   ENABLED_LAYERS_ENV, vk_instance_layers_env);
772
0
    }
773
0
    for (uint32_t i = 0; i < instance_layers->count; i++) {
774
0
        bool enable_layer = false;
775
0
        struct loader_layer_properties* props = &instance_layers->list[i];
776
777
        // Skip the sentinel unordered layer location
778
0
        if (props->settings_control_value == LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION) {
779
0
            continue;
780
0
        }
781
782
        // Do not enable the layer if the settings have it set as off
783
0
        if (props->settings_control_value == LOADER_SETTINGS_LAYER_CONTROL_OFF) {
784
0
            continue;
785
0
        }
786
        // Force enable it based on settings
787
0
        if (props->settings_control_value == LOADER_SETTINGS_LAYER_CONTROL_ON) {
788
0
            enable_layer = true;
789
0
            props->enabled_by_what = ENABLED_BY_WHAT_LOADER_SETTINGS_FILE;
790
0
        } else {
791
            // Check if disable filter needs to skip the layer
792
0
            if ((filters->disable_filter.disable_all || filters->disable_filter.disable_all_implicit ||
793
0
                 check_name_matches_filter_environment_var(props->info.layerName, &filters->disable_filter.additional_filters)) &&
794
0
                !check_name_matches_filter_environment_var(props->info.layerName, &filters->allow_filter)) {
795
                // Report a message that we've forced off a layer if it would have been enabled normally.
796
0
                loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
797
0
                           "Layer \"%s\" forced disabled because name matches filter of env var \'%s\'.", props->info.layerName,
798
0
                           VK_LAYERS_DISABLE_ENV_VAR);
799
800
0
                continue;
801
0
            }
802
0
        }
803
        // Check the enable filter
804
0
        if (!enable_layer && check_name_matches_filter_environment_var(props->info.layerName, &filters->enable_filter)) {
805
0
            enable_layer = true;
806
0
            props->enabled_by_what = ENABLED_BY_WHAT_VK_LOADER_LAYERS_ENABLE;
807
0
            loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
808
0
                       "Layer \"%s\" forced enabled due to env var \'%s\'.", props->info.layerName, VK_LAYERS_ENABLE_ENV_VAR);
809
0
        }
810
811
        // First look for the old-fashion layers forced on with VK_INSTANCE_LAYERS
812
0
        if (!enable_layer && vk_instance_layers_env && vk_instance_layers_env_copy && vk_instance_layers_env_len > 0) {
813
            // Copy the env-var on each iteration, so that loader_get_next_path can correctly find the separators
814
            // This solution only needs one stack allocation ahead of time rather than an allocation per layer in the
815
            // env-var
816
0
            loader_strncpy(vk_instance_layers_env_copy, vk_instance_layers_env_len, vk_instance_layers_env,
817
0
                           vk_instance_layers_env_len);
818
819
0
            char* instance_layers_env_iter = vk_instance_layers_env_copy;
820
0
            while (instance_layers_env_iter && *instance_layers_env_iter) {
821
0
                char* next = loader_get_next_path(instance_layers_env_iter);
822
0
                if (0 == strcmp(instance_layers_env_iter, props->info.layerName)) {
823
0
                    enable_layer = true;
824
0
                    props->enabled_by_what = ENABLED_BY_WHAT_VK_INSTANCE_LAYERS;
825
0
                    break;
826
0
                }
827
0
                instance_layers_env_iter = next;
828
0
            }
829
0
        }
830
831
        // Check if it should be enabled by the application
832
0
        if (!enable_layer) {
833
0
            for (uint32_t j = 0; j < app_enabled_name_count; j++) {
834
0
                if (strcmp(props->info.layerName, app_enabled_names[j]) == 0) {
835
0
                    enable_layer = true;
836
0
                    props->enabled_by_what = ENABLED_BY_WHAT_IN_APPLICATION_API;
837
0
                    break;
838
0
                }
839
0
            }
840
0
        }
841
842
        // Check if its an implicit layers and thus enabled by default
843
0
        if (!enable_layer && (0 == (props->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER)) &&
844
0
            loader_implicit_layer_is_enabled(inst, filters, props)) {
845
0
            enable_layer = true;
846
0
            props->enabled_by_what = ENABLED_BY_WHAT_IMPLICIT_LAYER;
847
0
        }
848
849
0
        if (enable_layer) {
850
            // Check if the layer is a meta layer reuse the existing function to add the meta layer
851
0
            if (props->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER) {
852
0
                res = loader_add_meta_layer(inst, filters, props, target_layer_list, activated_layer_list, instance_layers, NULL);
853
0
                if (res == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
854
0
            } else {
855
0
                res = loader_add_layer_properties_to_list(inst, target_layer_list, props);
856
0
                if (res != VK_SUCCESS) {
857
0
                    goto out;
858
0
                }
859
0
                res = loader_add_layer_properties_to_list(inst, activated_layer_list, props);
860
0
                if (res != VK_SUCCESS) {
861
0
                    goto out;
862
0
                }
863
0
            }
864
0
        }
865
0
    }
866
0
out:
867
0
    return res;
868
0
}