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