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