15db71995Sopenharmony_ci/*
25db71995Sopenharmony_ci *
35db71995Sopenharmony_ci * Copyright (c) 2023 The Khronos Group Inc.
45db71995Sopenharmony_ci * Copyright (c) 2023 Valve Corporation
55db71995Sopenharmony_ci * Copyright (c) 2023 LunarG, Inc.
65db71995Sopenharmony_ci *
75db71995Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
85db71995Sopenharmony_ci * you may not use this file except in compliance with the License.
95db71995Sopenharmony_ci * You may obtain a copy of the License at
105db71995Sopenharmony_ci *
115db71995Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
125db71995Sopenharmony_ci *
135db71995Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
145db71995Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
155db71995Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
165db71995Sopenharmony_ci * See the License for the specific language governing permissions and
175db71995Sopenharmony_ci * limitations under the License.
185db71995Sopenharmony_ci *
195db71995Sopenharmony_ci *
205db71995Sopenharmony_ci * Author: Charles Giessen <charles@lunarg.com>
215db71995Sopenharmony_ci *
225db71995Sopenharmony_ci */
235db71995Sopenharmony_ci
245db71995Sopenharmony_ci#include "settings.h"
255db71995Sopenharmony_ci
265db71995Sopenharmony_ci#include "allocation.h"
275db71995Sopenharmony_ci#include "cJSON.h"
285db71995Sopenharmony_ci#include "loader.h"
295db71995Sopenharmony_ci#include "loader_environment.h"
305db71995Sopenharmony_ci#include "loader_windows.h"
315db71995Sopenharmony_ci#include "log.h"
325db71995Sopenharmony_ci#include "stack_allocation.h"
335db71995Sopenharmony_ci#include "vk_loader_platform.h"
345db71995Sopenharmony_ci
355db71995Sopenharmony_ciloader_platform_thread_mutex global_loader_settings_lock;
365db71995Sopenharmony_ciloader_settings global_loader_settings;
375db71995Sopenharmony_ci
385db71995Sopenharmony_civoid free_layer_configuration(const struct loader_instance* inst, loader_settings_layer_configuration* layer_configuration) {
395db71995Sopenharmony_ci    loader_instance_heap_free(inst, layer_configuration->name);
405db71995Sopenharmony_ci    loader_instance_heap_free(inst, layer_configuration->path);
415db71995Sopenharmony_ci    memset(layer_configuration, 0, sizeof(loader_settings_layer_configuration));
425db71995Sopenharmony_ci}
435db71995Sopenharmony_ci
445db71995Sopenharmony_civoid free_loader_settings(const struct loader_instance* inst, loader_settings* settings) {
455db71995Sopenharmony_ci    if (NULL != settings->layer_configurations) {
465db71995Sopenharmony_ci        for (uint32_t i = 0; i < settings->layer_configuration_count; i++) {
475db71995Sopenharmony_ci            free_layer_configuration(inst, &settings->layer_configurations[i]);
485db71995Sopenharmony_ci        }
495db71995Sopenharmony_ci    }
505db71995Sopenharmony_ci    loader_instance_heap_free(inst, settings->layer_configurations);
515db71995Sopenharmony_ci    loader_instance_heap_free(inst, settings->settings_file_path);
525db71995Sopenharmony_ci    memset(settings, 0, sizeof(loader_settings));
535db71995Sopenharmony_ci}
545db71995Sopenharmony_ci
555db71995Sopenharmony_ciloader_settings_layer_control parse_control_string(char* control_string) {
565db71995Sopenharmony_ci    loader_settings_layer_control layer_control = LOADER_SETTINGS_LAYER_CONTROL_DEFAULT;
575db71995Sopenharmony_ci    if (strcmp(control_string, "auto") == 0)
585db71995Sopenharmony_ci        layer_control = LOADER_SETTINGS_LAYER_CONTROL_DEFAULT;
595db71995Sopenharmony_ci    else if (strcmp(control_string, "on") == 0)
605db71995Sopenharmony_ci        layer_control = LOADER_SETTINGS_LAYER_CONTROL_ON;
615db71995Sopenharmony_ci    else if (strcmp(control_string, "off") == 0)
625db71995Sopenharmony_ci        layer_control = LOADER_SETTINGS_LAYER_CONTROL_OFF;
635db71995Sopenharmony_ci    else if (strcmp(control_string, "unordered_layer_location") == 0)
645db71995Sopenharmony_ci        layer_control = LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION;
655db71995Sopenharmony_ci    return layer_control;
665db71995Sopenharmony_ci}
675db71995Sopenharmony_ci
685db71995Sopenharmony_ciconst char* loader_settings_layer_control_to_string(loader_settings_layer_control control) {
695db71995Sopenharmony_ci    switch (control) {
705db71995Sopenharmony_ci        case (LOADER_SETTINGS_LAYER_CONTROL_DEFAULT):
715db71995Sopenharmony_ci            return "auto";
725db71995Sopenharmony_ci        case (LOADER_SETTINGS_LAYER_CONTROL_ON):
735db71995Sopenharmony_ci            return "on";
745db71995Sopenharmony_ci        case (LOADER_SETTINGS_LAYER_CONTROL_OFF):
755db71995Sopenharmony_ci            return "off";
765db71995Sopenharmony_ci        case (LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION):
775db71995Sopenharmony_ci            return "unordered_layer_location";
785db71995Sopenharmony_ci        default:
795db71995Sopenharmony_ci            return "UNKNOWN_LAYER_CONTROl";
805db71995Sopenharmony_ci    }
815db71995Sopenharmony_ci}
825db71995Sopenharmony_ci
835db71995Sopenharmony_ciuint32_t parse_log_filters_from_strings(struct loader_string_list* log_filters) {
845db71995Sopenharmony_ci    uint32_t filters = 0;
855db71995Sopenharmony_ci    for (uint32_t i = 0; i < log_filters->count; i++) {
865db71995Sopenharmony_ci        if (strcmp(log_filters->list[i], "all") == 0)
875db71995Sopenharmony_ci            filters |= VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_PERF_BIT | VULKAN_LOADER_ERROR_BIT |
885db71995Sopenharmony_ci                       VULKAN_LOADER_DEBUG_BIT | VULKAN_LOADER_LAYER_BIT | VULKAN_LOADER_DRIVER_BIT | VULKAN_LOADER_VALIDATION_BIT;
895db71995Sopenharmony_ci        else if (strcmp(log_filters->list[i], "info") == 0)
905db71995Sopenharmony_ci            filters |= VULKAN_LOADER_INFO_BIT;
915db71995Sopenharmony_ci        else if (strcmp(log_filters->list[i], "warn") == 0)
925db71995Sopenharmony_ci            filters |= VULKAN_LOADER_WARN_BIT;
935db71995Sopenharmony_ci        else if (strcmp(log_filters->list[i], "perf") == 0)
945db71995Sopenharmony_ci            filters |= VULKAN_LOADER_PERF_BIT;
955db71995Sopenharmony_ci        else if (strcmp(log_filters->list[i], "error") == 0)
965db71995Sopenharmony_ci            filters |= VULKAN_LOADER_ERROR_BIT;
975db71995Sopenharmony_ci        else if (strcmp(log_filters->list[i], "debug") == 0)
985db71995Sopenharmony_ci            filters |= VULKAN_LOADER_DEBUG_BIT;
995db71995Sopenharmony_ci        else if (strcmp(log_filters->list[i], "layer") == 0)
1005db71995Sopenharmony_ci            filters |= VULKAN_LOADER_LAYER_BIT;
1015db71995Sopenharmony_ci        else if (strcmp(log_filters->list[i], "driver") == 0)
1025db71995Sopenharmony_ci            filters |= VULKAN_LOADER_DRIVER_BIT;
1035db71995Sopenharmony_ci        else if (strcmp(log_filters->list[i], "validation") == 0)
1045db71995Sopenharmony_ci            filters |= VULKAN_LOADER_VALIDATION_BIT;
1055db71995Sopenharmony_ci    }
1065db71995Sopenharmony_ci    return filters;
1075db71995Sopenharmony_ci}
1085db71995Sopenharmony_ci
1095db71995Sopenharmony_cibool parse_json_enable_disable_option(const struct loader_instance* inst, cJSON* object, const char* key) {
1105db71995Sopenharmony_ci    char* str = NULL;
1115db71995Sopenharmony_ci    VkResult res = loader_parse_json_string(object, key, &str);
1125db71995Sopenharmony_ci    if (res != VK_SUCCESS || NULL == str) {
1135db71995Sopenharmony_ci        return false;
1145db71995Sopenharmony_ci    }
1155db71995Sopenharmony_ci    bool enable = false;
1165db71995Sopenharmony_ci    if (strcmp(str, "enabled") == 0) {
1175db71995Sopenharmony_ci        enable = true;
1185db71995Sopenharmony_ci    }
1195db71995Sopenharmony_ci    loader_instance_heap_free(inst, str);
1205db71995Sopenharmony_ci    return enable;
1215db71995Sopenharmony_ci}
1225db71995Sopenharmony_ci
1235db71995Sopenharmony_ciVkResult parse_layer_configuration(const struct loader_instance* inst, cJSON* layer_configuration_json,
1245db71995Sopenharmony_ci                                   loader_settings_layer_configuration* layer_configuration) {
1255db71995Sopenharmony_ci    char* control_string = NULL;
1265db71995Sopenharmony_ci    VkResult res = loader_parse_json_string(layer_configuration_json, "control", &control_string);
1275db71995Sopenharmony_ci    if (res != VK_SUCCESS) {
1285db71995Sopenharmony_ci        goto out;
1295db71995Sopenharmony_ci    }
1305db71995Sopenharmony_ci    layer_configuration->control = parse_control_string(control_string);
1315db71995Sopenharmony_ci    loader_instance_heap_free(inst, control_string);
1325db71995Sopenharmony_ci
1335db71995Sopenharmony_ci    // If that is the only value - do no further parsing
1345db71995Sopenharmony_ci    if (layer_configuration->control == LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION) {
1355db71995Sopenharmony_ci        goto out;
1365db71995Sopenharmony_ci    }
1375db71995Sopenharmony_ci
1385db71995Sopenharmony_ci    res = loader_parse_json_string(layer_configuration_json, "name", &(layer_configuration->name));
1395db71995Sopenharmony_ci    if (res != VK_SUCCESS) {
1405db71995Sopenharmony_ci        goto out;
1415db71995Sopenharmony_ci    }
1425db71995Sopenharmony_ci
1435db71995Sopenharmony_ci    res = loader_parse_json_string(layer_configuration_json, "path", &(layer_configuration->path));
1445db71995Sopenharmony_ci    if (res != VK_SUCCESS) {
1455db71995Sopenharmony_ci        goto out;
1465db71995Sopenharmony_ci    }
1475db71995Sopenharmony_ci
1485db71995Sopenharmony_ci    cJSON* treat_as_implicit_manifest = loader_cJSON_GetObjectItem(layer_configuration_json, "treat_as_implicit_manifest");
1495db71995Sopenharmony_ci    if (treat_as_implicit_manifest && treat_as_implicit_manifest->type == cJSON_True) {
1505db71995Sopenharmony_ci        layer_configuration->treat_as_implicit_manifest = true;
1515db71995Sopenharmony_ci    }
1525db71995Sopenharmony_ciout:
1535db71995Sopenharmony_ci    if (VK_SUCCESS != res) {
1545db71995Sopenharmony_ci        free_layer_configuration(inst, layer_configuration);
1555db71995Sopenharmony_ci    }
1565db71995Sopenharmony_ci    return res;
1575db71995Sopenharmony_ci}
1585db71995Sopenharmony_ci
1595db71995Sopenharmony_ciVkResult parse_layer_configurations(const struct loader_instance* inst, cJSON* settings_object, loader_settings* loader_settings) {
1605db71995Sopenharmony_ci    VkResult res = VK_SUCCESS;
1615db71995Sopenharmony_ci
1625db71995Sopenharmony_ci    cJSON* layer_configurations = loader_cJSON_GetObjectItem(settings_object, "layers");
1635db71995Sopenharmony_ci    if (NULL == layer_configurations) {
1645db71995Sopenharmony_ci        return VK_ERROR_INITIALIZATION_FAILED;
1655db71995Sopenharmony_ci    }
1665db71995Sopenharmony_ci
1675db71995Sopenharmony_ci    uint32_t layer_configurations_count = loader_cJSON_GetArraySize(layer_configurations);
1685db71995Sopenharmony_ci    if (layer_configurations_count == 0) {
1695db71995Sopenharmony_ci        return VK_SUCCESS;
1705db71995Sopenharmony_ci    }
1715db71995Sopenharmony_ci
1725db71995Sopenharmony_ci    loader_settings->layer_configuration_count = layer_configurations_count;
1735db71995Sopenharmony_ci
1745db71995Sopenharmony_ci    loader_settings->layer_configurations = loader_instance_heap_calloc(
1755db71995Sopenharmony_ci        inst, sizeof(loader_settings_layer_configuration) * layer_configurations_count, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1765db71995Sopenharmony_ci    if (NULL == loader_settings->layer_configurations) {
1775db71995Sopenharmony_ci        res = VK_ERROR_OUT_OF_HOST_MEMORY;
1785db71995Sopenharmony_ci        goto out;
1795db71995Sopenharmony_ci    }
1805db71995Sopenharmony_ci
1815db71995Sopenharmony_ci    for (uint32_t i = 0; i < layer_configurations_count; i++) {
1825db71995Sopenharmony_ci        cJSON* layer = loader_cJSON_GetArrayItem(layer_configurations, i);
1835db71995Sopenharmony_ci        if (NULL == layer) {
1845db71995Sopenharmony_ci            res = VK_ERROR_INITIALIZATION_FAILED;
1855db71995Sopenharmony_ci            goto out;
1865db71995Sopenharmony_ci        }
1875db71995Sopenharmony_ci        res = parse_layer_configuration(inst, layer, &(loader_settings->layer_configurations[i]));
1885db71995Sopenharmony_ci        if (VK_SUCCESS != res) {
1895db71995Sopenharmony_ci            goto out;
1905db71995Sopenharmony_ci        }
1915db71995Sopenharmony_ci    }
1925db71995Sopenharmony_ciout:
1935db71995Sopenharmony_ci    if (res != VK_SUCCESS) {
1945db71995Sopenharmony_ci        if (loader_settings->layer_configurations) {
1955db71995Sopenharmony_ci            for (uint32_t i = 0; i < loader_settings->layer_configuration_count; i++) {
1965db71995Sopenharmony_ci                free_layer_configuration(inst, &(loader_settings->layer_configurations[i]));
1975db71995Sopenharmony_ci            }
1985db71995Sopenharmony_ci            loader_settings->layer_configuration_count = 0;
1995db71995Sopenharmony_ci            loader_instance_heap_free(inst, loader_settings->layer_configurations);
2005db71995Sopenharmony_ci            loader_settings->layer_configurations = NULL;
2015db71995Sopenharmony_ci        }
2025db71995Sopenharmony_ci    }
2035db71995Sopenharmony_ci
2045db71995Sopenharmony_ci    return res;
2055db71995Sopenharmony_ci}
2065db71995Sopenharmony_ci
2075db71995Sopenharmony_ciVkResult check_if_settings_path_exists(const struct loader_instance* inst, char* base, char* suffix, char** settings_file_path) {
2085db71995Sopenharmony_ci    if (NULL == base || NULL == suffix) {
2095db71995Sopenharmony_ci        return VK_ERROR_INITIALIZATION_FAILED;
2105db71995Sopenharmony_ci    }
2115db71995Sopenharmony_ci    size_t base_len = strlen(base);
2125db71995Sopenharmony_ci    size_t suffix_len = strlen(suffix);
2135db71995Sopenharmony_ci    size_t path_len = base_len + suffix_len + 1;
2145db71995Sopenharmony_ci    *settings_file_path = loader_instance_heap_calloc(inst, path_len, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
2155db71995Sopenharmony_ci    if (NULL == *settings_file_path) {
2165db71995Sopenharmony_ci        return VK_ERROR_OUT_OF_HOST_MEMORY;
2175db71995Sopenharmony_ci    }
2185db71995Sopenharmony_ci    loader_strncpy(*settings_file_path, path_len, base, base_len);
2195db71995Sopenharmony_ci    loader_strncat(*settings_file_path, path_len, suffix, suffix_len);
2205db71995Sopenharmony_ci
2215db71995Sopenharmony_ci    if (!loader_platform_file_exists(*settings_file_path)) {
2225db71995Sopenharmony_ci        loader_instance_heap_free(inst, *settings_file_path);
2235db71995Sopenharmony_ci        *settings_file_path = NULL;
2245db71995Sopenharmony_ci        return VK_ERROR_INITIALIZATION_FAILED;
2255db71995Sopenharmony_ci    }
2265db71995Sopenharmony_ci    return VK_SUCCESS;
2275db71995Sopenharmony_ci}
2285db71995Sopenharmony_ciVkResult get_unix_settings_path(const struct loader_instance* inst, char** settings_file_path) {
2295db71995Sopenharmony_ci    VkResult res =
2305db71995Sopenharmony_ci        check_if_settings_path_exists(inst, loader_secure_getenv("HOME", inst),
2315db71995Sopenharmony_ci                                      "/.local/share/vulkan/loader_settings.d/" VK_LOADER_SETTINGS_FILENAME, settings_file_path);
2325db71995Sopenharmony_ci    if (res == VK_SUCCESS) {
2335db71995Sopenharmony_ci        return res;
2345db71995Sopenharmony_ci    }
2355db71995Sopenharmony_ci    // If HOME isn't set, fallback to XDG_DATA_HOME
2365db71995Sopenharmony_ci    res = check_if_settings_path_exists(inst, loader_secure_getenv("XDG_DATA_HOME", inst),
2375db71995Sopenharmony_ci                                        "/vulkan/loader_settings.d/" VK_LOADER_SETTINGS_FILENAME, settings_file_path);
2385db71995Sopenharmony_ci    if (res == VK_SUCCESS) {
2395db71995Sopenharmony_ci        return res;
2405db71995Sopenharmony_ci    }
2415db71995Sopenharmony_ci    // if XDG_DATA_HOME isn't set, fallback to /etc.
2425db71995Sopenharmony_ci    // note that the settings_fil_path_suffix stays the same since its the same layout as for XDG_DATA_HOME
2435db71995Sopenharmony_ci    return check_if_settings_path_exists(inst, "/etc", "/vulkan/loader_settings.d/" VK_LOADER_SETTINGS_FILENAME,
2445db71995Sopenharmony_ci                                         settings_file_path);
2455db71995Sopenharmony_ci}
2465db71995Sopenharmony_ci
2475db71995Sopenharmony_cibool check_if_settings_are_equal(loader_settings* a, loader_settings* b) {
2485db71995Sopenharmony_ci    // If either pointer is null, return true
2495db71995Sopenharmony_ci    if (NULL == a || NULL == b) return false;
2505db71995Sopenharmony_ci    bool are_equal = true;
2515db71995Sopenharmony_ci    are_equal &= a->settings_active == b->settings_active;
2525db71995Sopenharmony_ci    are_equal &= a->has_unordered_layer_location == b->has_unordered_layer_location;
2535db71995Sopenharmony_ci    are_equal &= a->debug_level == b->debug_level;
2545db71995Sopenharmony_ci    are_equal &= a->layer_configuration_count == b->layer_configuration_count;
2555db71995Sopenharmony_ci    if (!are_equal) return false;
2565db71995Sopenharmony_ci    for (uint32_t i = 0; i < a->layer_configuration_count && i < b->layer_configuration_count; i++) {
2575db71995Sopenharmony_ci        if (a->layer_configurations[i].name && b->layer_configurations[i].name) {
2585db71995Sopenharmony_ci            are_equal &= 0 == strcmp(a->layer_configurations[i].name, b->layer_configurations[i].name);
2595db71995Sopenharmony_ci        } else {
2605db71995Sopenharmony_ci            are_equal = false;
2615db71995Sopenharmony_ci        }
2625db71995Sopenharmony_ci        if (a->layer_configurations[i].path && b->layer_configurations[i].path) {
2635db71995Sopenharmony_ci            are_equal &= 0 == strcmp(a->layer_configurations[i].path, b->layer_configurations[i].path);
2645db71995Sopenharmony_ci        } else {
2655db71995Sopenharmony_ci            are_equal = false;
2665db71995Sopenharmony_ci        }
2675db71995Sopenharmony_ci        are_equal &= a->layer_configurations[i].control == b->layer_configurations[i].control;
2685db71995Sopenharmony_ci    }
2695db71995Sopenharmony_ci    return are_equal;
2705db71995Sopenharmony_ci}
2715db71995Sopenharmony_ci
2725db71995Sopenharmony_civoid log_settings(const struct loader_instance* inst, loader_settings* settings) {
2735db71995Sopenharmony_ci    if (settings == NULL) {
2745db71995Sopenharmony_ci        return;
2755db71995Sopenharmony_ci    }
2765db71995Sopenharmony_ci    loader_log(inst, VULKAN_LOADER_INFO_BIT, 0, "Using layer configurations found in loader settings from %s",
2775db71995Sopenharmony_ci               settings->settings_file_path);
2785db71995Sopenharmony_ci
2795db71995Sopenharmony_ci    loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "Layer Configurations count = %d", settings->layer_configuration_count);
2805db71995Sopenharmony_ci    for (uint32_t i = 0; i < settings->layer_configuration_count; i++) {
2815db71995Sopenharmony_ci        loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "---- Layer Configuration [%d] ----", i);
2825db71995Sopenharmony_ci        if (settings->layer_configurations[i].control != LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION) {
2835db71995Sopenharmony_ci            loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "Name: %s", settings->layer_configurations[i].name);
2845db71995Sopenharmony_ci            loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "Path: %s", settings->layer_configurations[i].path);
2855db71995Sopenharmony_ci        }
2865db71995Sopenharmony_ci        loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "Control: %s",
2875db71995Sopenharmony_ci                   loader_settings_layer_control_to_string(settings->layer_configurations[i].control));
2885db71995Sopenharmony_ci    }
2895db71995Sopenharmony_ci    loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "---------------------------------");
2905db71995Sopenharmony_ci}
2915db71995Sopenharmony_ci
2925db71995Sopenharmony_ci// Loads the vk_loader_settings.json file
2935db71995Sopenharmony_ci// Returns VK_SUCCESS if it was found & was successfully parsed. Otherwise, it returns VK_ERROR_INITIALIZATION_FAILED if it
2945db71995Sopenharmony_ci// wasn't found or failed to parse, and returns VK_ERROR_OUT_OF_HOST_MEMORY if it was unable to allocate enough memory.
2955db71995Sopenharmony_ciVkResult get_loader_settings(const struct loader_instance* inst, loader_settings* loader_settings) {
2965db71995Sopenharmony_ci    VkResult res = VK_SUCCESS;
2975db71995Sopenharmony_ci    cJSON* json = NULL;
2985db71995Sopenharmony_ci    char* file_format_version_string = NULL;
2995db71995Sopenharmony_ci    char* settings_file_path = NULL;
3005db71995Sopenharmony_ci#if defined(WIN32)
3015db71995Sopenharmony_ci    res = windows_get_loader_settings_file_path(inst, &settings_file_path);
3025db71995Sopenharmony_ci    if (res != VK_SUCCESS) {
3035db71995Sopenharmony_ci        goto out;
3045db71995Sopenharmony_ci    }
3055db71995Sopenharmony_ci
3065db71995Sopenharmony_ci#elif COMMON_UNIX_PLATFORMS
3075db71995Sopenharmony_ci    res = get_unix_settings_path(inst, &settings_file_path);
3085db71995Sopenharmony_ci    if (res != VK_SUCCESS) {
3095db71995Sopenharmony_ci        goto out;
3105db71995Sopenharmony_ci    }
3115db71995Sopenharmony_ci#else
3125db71995Sopenharmony_ci#warning "Unsupported platform - must specify platform specific location for vk_loader_settings.json"
3135db71995Sopenharmony_ci#endif
3145db71995Sopenharmony_ci
3155db71995Sopenharmony_ci    res = loader_get_json(inst, settings_file_path, &json);
3165db71995Sopenharmony_ci    // Make sure sure the top level json value is an object
3175db71995Sopenharmony_ci    if (res != VK_SUCCESS || NULL == json || json->type != 6) {
3185db71995Sopenharmony_ci        goto out;
3195db71995Sopenharmony_ci    }
3205db71995Sopenharmony_ci
3215db71995Sopenharmony_ci    res = loader_parse_json_string(json, "file_format_version", &file_format_version_string);
3225db71995Sopenharmony_ci    if (res != VK_SUCCESS) {
3235db71995Sopenharmony_ci        goto out;
3245db71995Sopenharmony_ci    }
3255db71995Sopenharmony_ci    uint32_t settings_array_count = 0;
3265db71995Sopenharmony_ci    bool has_multi_setting_file = false;
3275db71995Sopenharmony_ci    cJSON* settings_array = loader_cJSON_GetObjectItem(json, "settings_array");
3285db71995Sopenharmony_ci    cJSON* single_settings_object = loader_cJSON_GetObjectItem(json, "settings");
3295db71995Sopenharmony_ci    if (NULL != settings_array) {
3305db71995Sopenharmony_ci        has_multi_setting_file = true;
3315db71995Sopenharmony_ci        settings_array_count = loader_cJSON_GetArraySize(settings_array);
3325db71995Sopenharmony_ci    } else if (NULL != single_settings_object) {
3335db71995Sopenharmony_ci        settings_array_count = 1;
3345db71995Sopenharmony_ci    }
3355db71995Sopenharmony_ci
3365db71995Sopenharmony_ci    // Corresponds to the settings object that has no app keys
3375db71995Sopenharmony_ci    int global_settings_index = -1;
3385db71995Sopenharmony_ci    // Corresponds to the settings object which has a matching app key
3395db71995Sopenharmony_ci    int index_to_use = -1;
3405db71995Sopenharmony_ci
3415db71995Sopenharmony_ci    char current_process_path[1024];
3425db71995Sopenharmony_ci    bool valid_exe_path = NULL != loader_platform_executable_path(current_process_path, 1024);
3435db71995Sopenharmony_ci
3445db71995Sopenharmony_ci    for (int i = 0; i < (int)settings_array_count; i++) {
3455db71995Sopenharmony_ci        if (has_multi_setting_file) {
3465db71995Sopenharmony_ci            single_settings_object = loader_cJSON_GetArrayItem(settings_array, i);
3475db71995Sopenharmony_ci        }
3485db71995Sopenharmony_ci        cJSON* app_keys = loader_cJSON_GetObjectItem(single_settings_object, "app_keys");
3495db71995Sopenharmony_ci        if (NULL == app_keys) {
3505db71995Sopenharmony_ci            if (global_settings_index == -1) {
3515db71995Sopenharmony_ci                global_settings_index = i;  // use the first 'global' settings that has no app keys as the global one
3525db71995Sopenharmony_ci            }
3535db71995Sopenharmony_ci            continue;
3545db71995Sopenharmony_ci        } else if (valid_exe_path) {
3555db71995Sopenharmony_ci            int app_key_count = loader_cJSON_GetArraySize(app_keys);
3565db71995Sopenharmony_ci            if (app_key_count == 0) {
3575db71995Sopenharmony_ci                continue;  // empty array
3585db71995Sopenharmony_ci            }
3595db71995Sopenharmony_ci            for (int j = 0; j < app_key_count; j++) {
3605db71995Sopenharmony_ci                cJSON* app_key_json = loader_cJSON_GetArrayItem(app_keys, j);
3615db71995Sopenharmony_ci                if (NULL == app_key_json) {
3625db71995Sopenharmony_ci                    continue;
3635db71995Sopenharmony_ci                }
3645db71995Sopenharmony_ci                char* app_key = loader_cJSON_Print(app_key_json);
3655db71995Sopenharmony_ci                if (NULL == app_key) {
3665db71995Sopenharmony_ci                    continue;
3675db71995Sopenharmony_ci                }
3685db71995Sopenharmony_ci
3695db71995Sopenharmony_ci                if (strcmp(current_process_path, app_key) == 0) {
3705db71995Sopenharmony_ci                    index_to_use = i;
3715db71995Sopenharmony_ci                }
3725db71995Sopenharmony_ci                loader_instance_heap_free(inst, app_key);
3735db71995Sopenharmony_ci                if (index_to_use == i) {
3745db71995Sopenharmony_ci                    break;  // break only after freeing the app key
3755db71995Sopenharmony_ci                }
3765db71995Sopenharmony_ci            }
3775db71995Sopenharmony_ci        }
3785db71995Sopenharmony_ci    }
3795db71995Sopenharmony_ci
3805db71995Sopenharmony_ci    // No app specific settings match - either use global settings or exit
3815db71995Sopenharmony_ci    if (index_to_use == -1) {
3825db71995Sopenharmony_ci        if (global_settings_index == -1) {
3835db71995Sopenharmony_ci            goto out;  // No global settings were found - exit
3845db71995Sopenharmony_ci        } else {
3855db71995Sopenharmony_ci            index_to_use = global_settings_index;  // Global settings are present - use it
3865db71995Sopenharmony_ci        }
3875db71995Sopenharmony_ci    }
3885db71995Sopenharmony_ci
3895db71995Sopenharmony_ci    // Now get the actual settings object to use - already have it if there is only one settings object
3905db71995Sopenharmony_ci    // If there are multiple settings, just need to set single_settings_object to the desired settings object
3915db71995Sopenharmony_ci    if (has_multi_setting_file) {
3925db71995Sopenharmony_ci        single_settings_object = loader_cJSON_GetArrayItem(settings_array, index_to_use);
3935db71995Sopenharmony_ci        if (NULL == single_settings_object) {
3945db71995Sopenharmony_ci            res = VK_ERROR_INITIALIZATION_FAILED;
3955db71995Sopenharmony_ci            goto out;
3965db71995Sopenharmony_ci        }
3975db71995Sopenharmony_ci    }
3985db71995Sopenharmony_ci
3995db71995Sopenharmony_ci    // optional
4005db71995Sopenharmony_ci    cJSON* stderr_filter = loader_cJSON_GetObjectItem(single_settings_object, "stderr_log");
4015db71995Sopenharmony_ci    if (NULL != stderr_filter) {
4025db71995Sopenharmony_ci        struct loader_string_list stderr_log = {0};
4035db71995Sopenharmony_ci        res = loader_parse_json_array_of_strings(inst, single_settings_object, "stderr_log", &stderr_log);
4045db71995Sopenharmony_ci        if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
4055db71995Sopenharmony_ci            goto out;
4065db71995Sopenharmony_ci        }
4075db71995Sopenharmony_ci        loader_settings->debug_level = parse_log_filters_from_strings(&stderr_log);
4085db71995Sopenharmony_ci        free_string_list(inst, &stderr_log);
4095db71995Sopenharmony_ci    }
4105db71995Sopenharmony_ci
4115db71995Sopenharmony_ci    // optional
4125db71995Sopenharmony_ci    cJSON* logs_to_use = loader_cJSON_GetObjectItem(single_settings_object, "log_locations");
4135db71995Sopenharmony_ci    if (NULL != logs_to_use) {
4145db71995Sopenharmony_ci        int log_count = loader_cJSON_GetArraySize(logs_to_use);
4155db71995Sopenharmony_ci        for (int i = 0; i < log_count; i++) {
4165db71995Sopenharmony_ci            cJSON* log_element = loader_cJSON_GetArrayItem(logs_to_use, i);
4175db71995Sopenharmony_ci            // bool is_valid = true;
4185db71995Sopenharmony_ci            if (NULL != log_element) {
4195db71995Sopenharmony_ci                struct loader_string_list log_destinations = {0};
4205db71995Sopenharmony_ci                res = loader_parse_json_array_of_strings(inst, log_element, "destinations", &log_destinations);
4215db71995Sopenharmony_ci                if (res != VK_SUCCESS) {
4225db71995Sopenharmony_ci                    // is_valid = false;
4235db71995Sopenharmony_ci                }
4245db71995Sopenharmony_ci                free_string_list(inst, &log_destinations);
4255db71995Sopenharmony_ci                struct loader_string_list log_filters = {0};
4265db71995Sopenharmony_ci                res = loader_parse_json_array_of_strings(inst, log_element, "filters", &log_filters);
4275db71995Sopenharmony_ci                if (res != VK_SUCCESS) {
4285db71995Sopenharmony_ci                    // is_valid = false;
4295db71995Sopenharmony_ci                }
4305db71995Sopenharmony_ci                free_string_list(inst, &log_filters);
4315db71995Sopenharmony_ci            }
4325db71995Sopenharmony_ci        }
4335db71995Sopenharmony_ci    }
4345db71995Sopenharmony_ci
4355db71995Sopenharmony_ci    res = parse_layer_configurations(inst, single_settings_object, loader_settings);
4365db71995Sopenharmony_ci    if (res != VK_SUCCESS) {
4375db71995Sopenharmony_ci        goto out;
4385db71995Sopenharmony_ci    }
4395db71995Sopenharmony_ci
4405db71995Sopenharmony_ci    // Determine if there exists a layer configuration indicating where to put layers not contained in the settings file
4415db71995Sopenharmony_ci    // LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION
4425db71995Sopenharmony_ci    for (uint32_t i = 0; i < loader_settings->layer_configuration_count; i++) {
4435db71995Sopenharmony_ci        if (loader_settings->layer_configurations[i].control == LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION) {
4445db71995Sopenharmony_ci            loader_settings->has_unordered_layer_location = true;
4455db71995Sopenharmony_ci            break;
4465db71995Sopenharmony_ci        }
4475db71995Sopenharmony_ci    }
4485db71995Sopenharmony_ci
4495db71995Sopenharmony_ci    loader_settings->settings_file_path = settings_file_path;
4505db71995Sopenharmony_ci    settings_file_path = NULL;
4515db71995Sopenharmony_ci    loader_settings->settings_active = true;
4525db71995Sopenharmony_ciout:
4535db71995Sopenharmony_ci    if (NULL != json) {
4545db71995Sopenharmony_ci        loader_cJSON_Delete(json);
4555db71995Sopenharmony_ci    }
4565db71995Sopenharmony_ci
4575db71995Sopenharmony_ci    loader_instance_heap_free(inst, settings_file_path);
4585db71995Sopenharmony_ci
4595db71995Sopenharmony_ci    loader_instance_heap_free(inst, file_format_version_string);
4605db71995Sopenharmony_ci    return res;
4615db71995Sopenharmony_ci}
4625db71995Sopenharmony_ci
4635db71995Sopenharmony_ciVkResult update_global_loader_settings(void) {
4645db71995Sopenharmony_ci    loader_settings settings = {0};
4655db71995Sopenharmony_ci    VkResult res = get_loader_settings(NULL, &settings);
4665db71995Sopenharmony_ci    loader_platform_thread_lock_mutex(&global_loader_settings_lock);
4675db71995Sopenharmony_ci
4685db71995Sopenharmony_ci    free_loader_settings(NULL, &global_loader_settings);
4695db71995Sopenharmony_ci    if (res == VK_SUCCESS) {
4705db71995Sopenharmony_ci        if (!check_if_settings_are_equal(&settings, &global_loader_settings)) {
4715db71995Sopenharmony_ci            log_settings(NULL, &settings);
4725db71995Sopenharmony_ci        }
4735db71995Sopenharmony_ci
4745db71995Sopenharmony_ci        memcpy(&global_loader_settings, &settings, sizeof(loader_settings));
4755db71995Sopenharmony_ci        if (global_loader_settings.settings_active) {
4765db71995Sopenharmony_ci            loader_set_global_debug_level(global_loader_settings.debug_level);
4775db71995Sopenharmony_ci        }
4785db71995Sopenharmony_ci    }
4795db71995Sopenharmony_ci    loader_platform_thread_unlock_mutex(&global_loader_settings_lock);
4805db71995Sopenharmony_ci    return res;
4815db71995Sopenharmony_ci}
4825db71995Sopenharmony_ci
4835db71995Sopenharmony_civoid init_global_loader_settings(void) {
4845db71995Sopenharmony_ci    loader_platform_thread_create_mutex(&global_loader_settings_lock);
4855db71995Sopenharmony_ci    // Free out the global settings in case the process was loaded & unloaded
4865db71995Sopenharmony_ci    free_loader_settings(NULL, &global_loader_settings);
4875db71995Sopenharmony_ci}
4885db71995Sopenharmony_civoid teardown_global_loader_settings(void) {
4895db71995Sopenharmony_ci    free_loader_settings(NULL, &global_loader_settings);
4905db71995Sopenharmony_ci    loader_platform_thread_delete_mutex(&global_loader_settings_lock);
4915db71995Sopenharmony_ci}
4925db71995Sopenharmony_ci
4935db71995Sopenharmony_cibool should_skip_logging_global_messages(VkFlags msg_type) {
4945db71995Sopenharmony_ci    loader_platform_thread_lock_mutex(&global_loader_settings_lock);
4955db71995Sopenharmony_ci    bool should_skip = global_loader_settings.settings_active && 0 != (msg_type & global_loader_settings.debug_level);
4965db71995Sopenharmony_ci    loader_platform_thread_unlock_mutex(&global_loader_settings_lock);
4975db71995Sopenharmony_ci    return should_skip;
4985db71995Sopenharmony_ci}
4995db71995Sopenharmony_ci
5005db71995Sopenharmony_ci// Use this function to get the correct settings to use based on the context
5015db71995Sopenharmony_ci// If inst is NULL - use the global settings and lock the mutex
5025db71995Sopenharmony_ci// Else return the settings local to the instance - but do nto lock the mutex
5035db71995Sopenharmony_ciconst loader_settings* get_current_settings_and_lock(const struct loader_instance* inst) {
5045db71995Sopenharmony_ci    if (inst) {
5055db71995Sopenharmony_ci        return &inst->settings;
5065db71995Sopenharmony_ci    }
5075db71995Sopenharmony_ci    loader_platform_thread_lock_mutex(&global_loader_settings_lock);
5085db71995Sopenharmony_ci    return &global_loader_settings;
5095db71995Sopenharmony_ci}
5105db71995Sopenharmony_ci// Release the global settings lock if we are using the global settings - aka if inst is NULL
5115db71995Sopenharmony_civoid release_current_settings_lock(const struct loader_instance* inst) {
5125db71995Sopenharmony_ci    if (inst == NULL) {
5135db71995Sopenharmony_ci        loader_platform_thread_unlock_mutex(&global_loader_settings_lock);
5145db71995Sopenharmony_ci    }
5155db71995Sopenharmony_ci}
5165db71995Sopenharmony_ci
5175db71995Sopenharmony_ciVkResult get_settings_layers(const struct loader_instance* inst, struct loader_layer_list* settings_layers,
5185db71995Sopenharmony_ci                             bool* should_search_for_other_layers) {
5195db71995Sopenharmony_ci    VkResult res = VK_SUCCESS;
5205db71995Sopenharmony_ci    *should_search_for_other_layers = true;  // default to true
5215db71995Sopenharmony_ci
5225db71995Sopenharmony_ci    const loader_settings* settings = get_current_settings_and_lock(inst);
5235db71995Sopenharmony_ci
5245db71995Sopenharmony_ci    if (NULL == settings || !settings->settings_active) {
5255db71995Sopenharmony_ci        goto out;
5265db71995Sopenharmony_ci    }
5275db71995Sopenharmony_ci
5285db71995Sopenharmony_ci    // Assume the list doesn't contain LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION at first
5295db71995Sopenharmony_ci    *should_search_for_other_layers = false;
5305db71995Sopenharmony_ci
5315db71995Sopenharmony_ci    for (uint32_t i = 0; i < settings->layer_configuration_count; i++) {
5325db71995Sopenharmony_ci        loader_settings_layer_configuration* layer_config = &settings->layer_configurations[i];
5335db71995Sopenharmony_ci
5345db71995Sopenharmony_ci        // If we encountered a layer that should be forced off, we add it to the settings_layers list but only
5355db71995Sopenharmony_ci        // with the data required to compare it with layers not in the settings file (aka name and manifest path)
5365db71995Sopenharmony_ci        if (layer_config->control == LOADER_SETTINGS_LAYER_CONTROL_OFF) {
5375db71995Sopenharmony_ci            struct loader_layer_properties props = {0};
5385db71995Sopenharmony_ci            props.settings_control_value = LOADER_SETTINGS_LAYER_CONTROL_OFF;
5395db71995Sopenharmony_ci            loader_strncpy(props.info.layerName, VK_MAX_EXTENSION_NAME_SIZE, layer_config->name, VK_MAX_EXTENSION_NAME_SIZE);
5405db71995Sopenharmony_ci            props.info.layerName[VK_MAX_EXTENSION_NAME_SIZE - 1] = '\0';
5415db71995Sopenharmony_ci            res = loader_copy_to_new_str(inst, layer_config->path, &props.manifest_file_name);
5425db71995Sopenharmony_ci            if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
5435db71995Sopenharmony_ci                goto out;
5445db71995Sopenharmony_ci            }
5455db71995Sopenharmony_ci            res = loader_append_layer_property(inst, settings_layers, &props);
5465db71995Sopenharmony_ci            if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
5475db71995Sopenharmony_ci                loader_free_layer_properties(inst, &props);
5485db71995Sopenharmony_ci                goto out;
5495db71995Sopenharmony_ci            }
5505db71995Sopenharmony_ci            continue;
5515db71995Sopenharmony_ci        }
5525db71995Sopenharmony_ci
5535db71995Sopenharmony_ci        // The special layer location that indicates where unordered layers should go only should have the
5545db71995Sopenharmony_ci        // settings_control_value set - everything else should be NULL
5555db71995Sopenharmony_ci        if (layer_config->control == LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION) {
5565db71995Sopenharmony_ci            struct loader_layer_properties props = {0};
5575db71995Sopenharmony_ci            props.settings_control_value = LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION;
5585db71995Sopenharmony_ci            res = loader_append_layer_property(inst, settings_layers, &props);
5595db71995Sopenharmony_ci            if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
5605db71995Sopenharmony_ci                loader_free_layer_properties(inst, &props);
5615db71995Sopenharmony_ci                goto out;
5625db71995Sopenharmony_ci            }
5635db71995Sopenharmony_ci            *should_search_for_other_layers = true;
5645db71995Sopenharmony_ci            continue;
5655db71995Sopenharmony_ci        }
5665db71995Sopenharmony_ci
5675db71995Sopenharmony_ci        if (layer_config->path == NULL) {
5685db71995Sopenharmony_ci            continue;
5695db71995Sopenharmony_ci        }
5705db71995Sopenharmony_ci
5715db71995Sopenharmony_ci        cJSON* json = NULL;
5725db71995Sopenharmony_ci        VkResult local_res = loader_get_json(inst, layer_config->path, &json);
5735db71995Sopenharmony_ci        if (VK_ERROR_OUT_OF_HOST_MEMORY == local_res) {
5745db71995Sopenharmony_ci            res = VK_ERROR_OUT_OF_HOST_MEMORY;
5755db71995Sopenharmony_ci            goto out;
5765db71995Sopenharmony_ci        } else if (VK_SUCCESS != local_res || NULL == json) {
5775db71995Sopenharmony_ci            continue;
5785db71995Sopenharmony_ci        }
5795db71995Sopenharmony_ci
5805db71995Sopenharmony_ci        local_res =
5815db71995Sopenharmony_ci            loader_add_layer_properties(inst, settings_layers, json, layer_config->treat_as_implicit_manifest, layer_config->path);
5825db71995Sopenharmony_ci        loader_cJSON_Delete(json);
5835db71995Sopenharmony_ci
5845db71995Sopenharmony_ci        // If the error is anything other than out of memory we still want to try to load the other layers
5855db71995Sopenharmony_ci        if (VK_ERROR_OUT_OF_HOST_MEMORY == local_res) {
5865db71995Sopenharmony_ci            res = VK_ERROR_OUT_OF_HOST_MEMORY;
5875db71995Sopenharmony_ci            goto out;
5885db71995Sopenharmony_ci        }
5895db71995Sopenharmony_ci        struct loader_layer_properties* newly_added_layer = &settings_layers->list[settings_layers->count - 1];
5905db71995Sopenharmony_ci        newly_added_layer->settings_control_value = layer_config->control;
5915db71995Sopenharmony_ci        // If the manifest file found has a name that differs from the one in the settings, remove this layer from consideration
5925db71995Sopenharmony_ci        bool should_remove = false;
5935db71995Sopenharmony_ci        if (strncmp(newly_added_layer->info.layerName, layer_config->name, VK_MAX_EXTENSION_NAME_SIZE) != 0) {
5945db71995Sopenharmony_ci            should_remove = true;
5955db71995Sopenharmony_ci            loader_remove_layer_in_list(inst, settings_layers, settings_layers->count - 1);
5965db71995Sopenharmony_ci        }
5975db71995Sopenharmony_ci        // Make sure the layer isn't already in the list
5985db71995Sopenharmony_ci        for (uint32_t j = 0; settings_layers->count > 0 && j < settings_layers->count - 1; j++) {
5995db71995Sopenharmony_ci            if (0 ==
6005db71995Sopenharmony_ci                strncmp(settings_layers->list[j].info.layerName, newly_added_layer->info.layerName, VK_MAX_EXTENSION_NAME_SIZE)) {
6015db71995Sopenharmony_ci                if (0 == (newly_added_layer->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER) &&
6025db71995Sopenharmony_ci                    strcmp(settings_layers->list[j].lib_name, newly_added_layer->lib_name) == 0) {
6035db71995Sopenharmony_ci                    should_remove = true;
6045db71995Sopenharmony_ci                    break;
6055db71995Sopenharmony_ci                }
6065db71995Sopenharmony_ci            }
6075db71995Sopenharmony_ci        }
6085db71995Sopenharmony_ci        if (should_remove) {
6095db71995Sopenharmony_ci            loader_remove_layer_in_list(inst, settings_layers, settings_layers->count - 1);
6105db71995Sopenharmony_ci        }
6115db71995Sopenharmony_ci    }
6125db71995Sopenharmony_ci
6135db71995Sopenharmony_ciout:
6145db71995Sopenharmony_ci    release_current_settings_lock(inst);
6155db71995Sopenharmony_ci    return res;
6165db71995Sopenharmony_ci}
6175db71995Sopenharmony_ci
6185db71995Sopenharmony_ci// Check if layers has an element with the same name.
6195db71995Sopenharmony_ci// If layer_property is a regular layer, check if the lib_path is the same.
6205db71995Sopenharmony_ci// If layer_property is a meta layer, just use the layerName
6215db71995Sopenharmony_cibool check_if_layer_is_in_list(struct loader_layer_list* layer_list, struct loader_layer_properties* layer_property) {
6225db71995Sopenharmony_ci    // If the layer is a meta layer, just check against the name
6235db71995Sopenharmony_ci    for (uint32_t i = 0; i < layer_list->count; i++) {
6245db71995Sopenharmony_ci        if (0 == strncmp(layer_list->list[i].info.layerName, layer_property->info.layerName, VK_MAX_EXTENSION_NAME_SIZE)) {
6255db71995Sopenharmony_ci            if (0 == (layer_property->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER) &&
6265db71995Sopenharmony_ci                strcmp(layer_list->list[i].lib_name, layer_property->lib_name) == 0) {
6275db71995Sopenharmony_ci                return true;
6285db71995Sopenharmony_ci            }
6295db71995Sopenharmony_ci        }
6305db71995Sopenharmony_ci    }
6315db71995Sopenharmony_ci    return false;
6325db71995Sopenharmony_ci}
6335db71995Sopenharmony_ci
6345db71995Sopenharmony_ciVkResult combine_settings_layers_with_regular_layers(const struct loader_instance* inst, struct loader_layer_list* settings_layers,
6355db71995Sopenharmony_ci                                                     struct loader_layer_list* regular_layers,
6365db71995Sopenharmony_ci                                                     struct loader_layer_list* output_layers) {
6375db71995Sopenharmony_ci    VkResult res = VK_SUCCESS;
6385db71995Sopenharmony_ci    bool has_unordered_layer_location = false;
6395db71995Sopenharmony_ci    uint32_t unordered_layer_location_index = 0;
6405db71995Sopenharmony_ci    // Location to put layers that aren't known to the settings file
6415db71995Sopenharmony_ci    // Find it here so we dont have to pass in a loader_settings struct
6425db71995Sopenharmony_ci    for (uint32_t i = 0; i < settings_layers->count; i++) {
6435db71995Sopenharmony_ci        if (settings_layers->list[i].settings_control_value == LOADER_SETTINGS_LAYER_UNORDERED_LAYER_LOCATION) {
6445db71995Sopenharmony_ci            has_unordered_layer_location = true;
6455db71995Sopenharmony_ci            unordered_layer_location_index = i;
6465db71995Sopenharmony_ci            break;
6475db71995Sopenharmony_ci        }
6485db71995Sopenharmony_ci    }
6495db71995Sopenharmony_ci
6505db71995Sopenharmony_ci    if (settings_layers->count == 0 && regular_layers->count == 0) {
6515db71995Sopenharmony_ci        // No layers to combine
6525db71995Sopenharmony_ci        goto out;
6535db71995Sopenharmony_ci    } else if (settings_layers->count == 0) {
6545db71995Sopenharmony_ci        // No settings layers - just copy regular to output_layers - memset regular layers to prevent double frees
6555db71995Sopenharmony_ci        *output_layers = *regular_layers;
6565db71995Sopenharmony_ci        memset(regular_layers, 0, sizeof(struct loader_layer_list));
6575db71995Sopenharmony_ci        goto out;
6585db71995Sopenharmony_ci    } else if (regular_layers->count == 0 || !has_unordered_layer_location) {
6595db71995Sopenharmony_ci        // No regular layers or has_unordered_layer_location is false - just copy settings to output_layers -
6605db71995Sopenharmony_ci        // memset settings layers to prevent double frees
6615db71995Sopenharmony_ci        *output_layers = *settings_layers;
6625db71995Sopenharmony_ci        memset(settings_layers, 0, sizeof(struct loader_layer_list));
6635db71995Sopenharmony_ci        goto out;
6645db71995Sopenharmony_ci    }
6655db71995Sopenharmony_ci
6665db71995Sopenharmony_ci    res = loader_init_generic_list(inst, (struct loader_generic_list*)output_layers,
6675db71995Sopenharmony_ci                                   (settings_layers->count + regular_layers->count) * sizeof(struct loader_layer_properties));
6685db71995Sopenharmony_ci    if (VK_SUCCESS != res) {
6695db71995Sopenharmony_ci        goto out;
6705db71995Sopenharmony_ci    }
6715db71995Sopenharmony_ci
6725db71995Sopenharmony_ci    // Insert the settings layers into output_layers up to unordered_layer_index
6735db71995Sopenharmony_ci    for (uint32_t i = 0; i < unordered_layer_location_index; i++) {
6745db71995Sopenharmony_ci        if (!check_if_layer_is_in_list(output_layers, &settings_layers->list[i])) {
6755db71995Sopenharmony_ci            res = loader_append_layer_property(inst, output_layers, &settings_layers->list[i]);
6765db71995Sopenharmony_ci            if (VK_SUCCESS != res) {
6775db71995Sopenharmony_ci                goto out;
6785db71995Sopenharmony_ci            }
6795db71995Sopenharmony_ci        }
6805db71995Sopenharmony_ci    }
6815db71995Sopenharmony_ci
6825db71995Sopenharmony_ci    for (uint32_t i = 0; i < regular_layers->count; i++) {
6835db71995Sopenharmony_ci        // Check if its already been put in the output_layers list as well as the remaining settings_layers
6845db71995Sopenharmony_ci        bool regular_layer_is_ordered = check_if_layer_is_in_list(output_layers, &regular_layers->list[i]) ||
6855db71995Sopenharmony_ci                                        check_if_layer_is_in_list(settings_layers, &regular_layers->list[i]);
6865db71995Sopenharmony_ci        // If it isn't found, add it
6875db71995Sopenharmony_ci        if (!regular_layer_is_ordered) {
6885db71995Sopenharmony_ci            res = loader_append_layer_property(inst, output_layers, &regular_layers->list[i]);
6895db71995Sopenharmony_ci            if (VK_SUCCESS != res) {
6905db71995Sopenharmony_ci                goto out;
6915db71995Sopenharmony_ci            }
6925db71995Sopenharmony_ci        } else {
6935db71995Sopenharmony_ci            // layer is already ordered and can be safely freed
6945db71995Sopenharmony_ci            loader_free_layer_properties(inst, &regular_layers->list[i]);
6955db71995Sopenharmony_ci        }
6965db71995Sopenharmony_ci    }
6975db71995Sopenharmony_ci
6985db71995Sopenharmony_ci    // Insert the rest of the settings layers into combined_layers from  unordered_layer_index to the end
6995db71995Sopenharmony_ci    // start at one after the unordered_layer_index
7005db71995Sopenharmony_ci    for (uint32_t i = unordered_layer_location_index + 1; i < settings_layers->count; i++) {
7015db71995Sopenharmony_ci        res = loader_append_layer_property(inst, output_layers, &settings_layers->list[i]);
7025db71995Sopenharmony_ci        if (VK_SUCCESS != res) {
7035db71995Sopenharmony_ci            goto out;
7045db71995Sopenharmony_ci        }
7055db71995Sopenharmony_ci    }
7065db71995Sopenharmony_ci
7075db71995Sopenharmony_ciout:
7085db71995Sopenharmony_ci    if (res != VK_SUCCESS) {
7095db71995Sopenharmony_ci        loader_delete_layer_list_and_properties(inst, output_layers);
7105db71995Sopenharmony_ci    }
7115db71995Sopenharmony_ci
7125db71995Sopenharmony_ci    return res;
7135db71995Sopenharmony_ci}
7145db71995Sopenharmony_ci
7155db71995Sopenharmony_ciVkResult enable_correct_layers_from_settings(const struct loader_instance* inst, const struct loader_envvar_all_filters* filters,
7165db71995Sopenharmony_ci                                             uint32_t app_enabled_name_count, const char* const* app_enabled_names,
7175db71995Sopenharmony_ci                                             const struct loader_layer_list* instance_layers,
7185db71995Sopenharmony_ci                                             struct loader_pointer_layer_list* target_layer_list,
7195db71995Sopenharmony_ci                                             struct loader_pointer_layer_list* activated_layer_list) {
7205db71995Sopenharmony_ci    VkResult res = VK_SUCCESS;
7215db71995Sopenharmony_ci    char* vk_instance_layers_env = loader_getenv(ENABLED_LAYERS_ENV, inst);
7225db71995Sopenharmony_ci    size_t vk_instance_layers_env_len = 0;
7235db71995Sopenharmony_ci    char* vk_instance_layers_env_copy = NULL;
7245db71995Sopenharmony_ci    if (vk_instance_layers_env != NULL) {
7255db71995Sopenharmony_ci        vk_instance_layers_env_len = strlen(vk_instance_layers_env) + 1;
7265db71995Sopenharmony_ci        vk_instance_layers_env_copy = loader_stack_alloc(vk_instance_layers_env_len);
7275db71995Sopenharmony_ci
7285db71995Sopenharmony_ci        loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0, "env var \'%s\' defined and adding layers: %s",
7295db71995Sopenharmony_ci                   ENABLED_LAYERS_ENV, vk_instance_layers_env);
7305db71995Sopenharmony_ci    }
7315db71995Sopenharmony_ci    for (uint32_t i = 0; i < instance_layers->count; i++) {
7325db71995Sopenharmony_ci        bool enable_layer = false;
7335db71995Sopenharmony_ci        struct loader_layer_properties* props = &instance_layers->list[i];
7345db71995Sopenharmony_ci
7355db71995Sopenharmony_ci        // Do not enable the layer if the settings have it set as off
7365db71995Sopenharmony_ci        if (props->settings_control_value == LOADER_SETTINGS_LAYER_CONTROL_OFF) {
7375db71995Sopenharmony_ci            continue;
7385db71995Sopenharmony_ci        }
7395db71995Sopenharmony_ci        // Force enable it based on settings
7405db71995Sopenharmony_ci        if (props->settings_control_value == LOADER_SETTINGS_LAYER_CONTROL_ON) {
7415db71995Sopenharmony_ci            enable_layer = true;
7425db71995Sopenharmony_ci        }
7435db71995Sopenharmony_ci
7445db71995Sopenharmony_ci        // Check if disable filter needs to skip the layer
7455db71995Sopenharmony_ci        if ((filters->disable_filter.disable_all || filters->disable_filter.disable_all_implicit ||
7465db71995Sopenharmony_ci             check_name_matches_filter_environment_var(props->info.layerName, &filters->disable_filter.additional_filters)) &&
7475db71995Sopenharmony_ci            !check_name_matches_filter_environment_var(props->info.layerName, &filters->allow_filter)) {
7485db71995Sopenharmony_ci            continue;
7495db71995Sopenharmony_ci        }
7505db71995Sopenharmony_ci        // Check the enable filter
7515db71995Sopenharmony_ci        if (!enable_layer && check_name_matches_filter_environment_var(props->info.layerName, &filters->enable_filter)) {
7525db71995Sopenharmony_ci            enable_layer = true;
7535db71995Sopenharmony_ci        }
7545db71995Sopenharmony_ci
7555db71995Sopenharmony_ci        // First look for the old-fashion layers forced on with VK_INSTANCE_LAYERS
7565db71995Sopenharmony_ci        if (!enable_layer && vk_instance_layers_env && vk_instance_layers_env_copy && vk_instance_layers_env_len > 0) {
7575db71995Sopenharmony_ci            // Copy the env-var on each iteration, so that loader_get_next_path can correctly find the separators
7585db71995Sopenharmony_ci            // This solution only needs one stack allocation ahead of time rather than an allocation per layer in the env-var
7595db71995Sopenharmony_ci            loader_strncpy(vk_instance_layers_env_copy, vk_instance_layers_env_len, vk_instance_layers_env,
7605db71995Sopenharmony_ci                           vk_instance_layers_env_len);
7615db71995Sopenharmony_ci
7625db71995Sopenharmony_ci            while (vk_instance_layers_env_copy && *vk_instance_layers_env_copy) {
7635db71995Sopenharmony_ci                char* next = loader_get_next_path(vk_instance_layers_env_copy);
7645db71995Sopenharmony_ci                if (0 == strcmp(vk_instance_layers_env_copy, props->info.layerName)) {
7655db71995Sopenharmony_ci                    enable_layer = true;
7665db71995Sopenharmony_ci                    break;
7675db71995Sopenharmony_ci                }
7685db71995Sopenharmony_ci                vk_instance_layers_env_copy = next;
7695db71995Sopenharmony_ci            }
7705db71995Sopenharmony_ci        }
7715db71995Sopenharmony_ci
7725db71995Sopenharmony_ci        // Check if it should be enabled by the application
7735db71995Sopenharmony_ci        if (!enable_layer) {
7745db71995Sopenharmony_ci            for (uint32_t j = 0; j < app_enabled_name_count; j++) {
7755db71995Sopenharmony_ci                if (strcmp(props->info.layerName, app_enabled_names[j]) == 0) {
7765db71995Sopenharmony_ci                    enable_layer = true;
7775db71995Sopenharmony_ci                    break;
7785db71995Sopenharmony_ci                }
7795db71995Sopenharmony_ci            }
7805db71995Sopenharmony_ci        }
7815db71995Sopenharmony_ci
7825db71995Sopenharmony_ci        // Check if its an implicit layers and thus enabled by default
7835db71995Sopenharmony_ci        if (!enable_layer && (0 == (props->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER)) &&
7845db71995Sopenharmony_ci            loader_implicit_layer_is_enabled(inst, filters, props)) {
7855db71995Sopenharmony_ci            enable_layer = true;
7865db71995Sopenharmony_ci        }
7875db71995Sopenharmony_ci
7885db71995Sopenharmony_ci        if (enable_layer) {
7895db71995Sopenharmony_ci            // Check if the layer is a meta layer reuse the existing function to add the meta layer
7905db71995Sopenharmony_ci            if (props->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER) {
7915db71995Sopenharmony_ci                res = loader_add_meta_layer(inst, filters, props, target_layer_list, activated_layer_list, instance_layers, NULL);
7925db71995Sopenharmony_ci                if (res == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
7935db71995Sopenharmony_ci            } else {
7945db71995Sopenharmony_ci                res = loader_add_layer_properties_to_list(inst, target_layer_list, props);
7955db71995Sopenharmony_ci                if (res != VK_SUCCESS) {
7965db71995Sopenharmony_ci                    goto out;
7975db71995Sopenharmony_ci                }
7985db71995Sopenharmony_ci                res = loader_add_layer_properties_to_list(inst, activated_layer_list, props);
7995db71995Sopenharmony_ci                if (res != VK_SUCCESS) {
8005db71995Sopenharmony_ci                    goto out;
8015db71995Sopenharmony_ci                }
8025db71995Sopenharmony_ci            }
8035db71995Sopenharmony_ci        }
8045db71995Sopenharmony_ci    }
8055db71995Sopenharmony_ciout:
8065db71995Sopenharmony_ci    return res;
8075db71995Sopenharmony_ci}
808