/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, ®ular_layers->list[i]) || |
726 | 0 | check_if_layer_is_in_list(settings_layers, ®ular_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, ®ular_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, ®ular_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 | } |