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