mirror of
https://gitee.com/openharmony/third_party_vulkan-loader
synced 2024-11-26 17:02:23 +00:00
0281b281d0
Signed-off-by: andrew0229 <zhangzhao62@huawei.com> Change-Id: Ifc4224db2c6ea7c159d3cabe8f075475d47a41a8
578 lines
25 KiB
C
578 lines
25 KiB
C
/*
|
|
*
|
|
* Copyright (c) 2014-2023 The Khronos Group Inc.
|
|
* Copyright (c) 2014-2023 Valve Corporation
|
|
* Copyright (c) 2014-2023 LunarG, Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
* Author: Jon Ashburn <jon@lunarg.com>
|
|
* Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
|
|
* Author: Chia-I Wu <olvaffe@gmail.com>
|
|
* Author: Chia-I Wu <olv@lunarg.com>
|
|
* Author: Mark Lobodzinski <mark@LunarG.com>
|
|
* Author: Lenny Komow <lenny@lunarg.com>
|
|
* Author: Charles Giessen <charles@lunarg.com>
|
|
*
|
|
*/
|
|
|
|
#include "loader_environment.h"
|
|
|
|
#include "allocation.h"
|
|
#include "loader.h"
|
|
#include "log.h"
|
|
|
|
#include <ctype.h>
|
|
#include "param/sys_param.h"
|
|
|
|
// Environment variables
|
|
#if COMMON_UNIX_PLATFORMS
|
|
|
|
bool is_high_integrity() { return geteuid() != getuid() || getegid() != getgid(); }
|
|
|
|
char *loader_getenv(const char *name, const struct loader_instance *inst) {
|
|
if (NULL == name) return NULL;
|
|
#if defined(__OHOS__)
|
|
CachedHandle g_Handle = CachedParameterCreate(name, "");
|
|
int changed = 0;
|
|
const char *res = CachedParameterGetChanged(g_Handle, &changed);
|
|
loader_log(inst, VULKAN_LOADER_DEBUG_BIT | VULKAN_LOADER_INFO_BIT, 0, "loader_getenv name:%s, res:%s", name, res);
|
|
if (res == NULL || res[0] == '\0') {
|
|
return NULL;
|
|
}
|
|
return (char *)res;
|
|
#else
|
|
// No allocation of memory necessary for Linux, but we should at least touch
|
|
// the inst pointer to get rid of compiler warnings.
|
|
(void)inst;
|
|
return getenv(name);
|
|
#endif
|
|
}
|
|
|
|
char *loader_secure_getenv(const char *name, const struct loader_instance *inst) {
|
|
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
|
|
// Apple does not appear to have a secure getenv implementation.
|
|
// The main difference between secure getenv and getenv is that secure getenv
|
|
// returns NULL if the process is being run with elevated privileges by a normal user.
|
|
// The idea is to prevent the reading of malicious environment variables by a process
|
|
// that can do damage.
|
|
// This algorithm is derived from glibc code that sets an internal
|
|
// variable (__libc_enable_secure) if the process is running under setuid or setgid.
|
|
return is_high_integrity() ? NULL : loader_getenv(name, inst);
|
|
#elif defined(__Fuchsia__)
|
|
return loader_getenv(name, inst);
|
|
#else
|
|
// Linux
|
|
char *out;
|
|
#if defined(HAVE_SECURE_GETENV) && !defined(LOADER_USE_UNSAFE_FILE_SEARCH)
|
|
(void)inst;
|
|
out = secure_getenv(name);
|
|
#elif defined(HAVE___SECURE_GETENV) && !defined(LOADER_USE_UNSAFE_FILE_SEARCH)
|
|
(void)inst;
|
|
out = __secure_getenv(name);
|
|
#else
|
|
out = loader_getenv(name, inst);
|
|
#if !defined(LOADER_USE_UNSAFE_FILE_SEARCH)
|
|
loader_log(inst, VULKAN_LOADER_INFO_BIT, 0, "Loader is using non-secure environment variable lookup for %s", name);
|
|
#endif
|
|
#endif
|
|
return out;
|
|
#endif
|
|
}
|
|
|
|
void loader_free_getenv(char *val, const struct loader_instance *inst) {
|
|
// No freeing of memory necessary for Linux, but we should at least touch
|
|
// the val and inst pointers to get rid of compiler warnings.
|
|
(void)val;
|
|
(void)inst;
|
|
}
|
|
|
|
#elif defined(WIN32)
|
|
|
|
bool is_high_integrity() {
|
|
HANDLE process_token;
|
|
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_QUERY_SOURCE, &process_token)) {
|
|
// Maximum possible size of SID_AND_ATTRIBUTES is maximum size of a SID + size of attributes DWORD.
|
|
uint8_t mandatory_label_buffer[SECURITY_MAX_SID_SIZE + sizeof(DWORD)];
|
|
DWORD buffer_size;
|
|
if (GetTokenInformation(process_token, TokenIntegrityLevel, mandatory_label_buffer, sizeof(mandatory_label_buffer),
|
|
&buffer_size) != 0) {
|
|
const TOKEN_MANDATORY_LABEL *mandatory_label = (const TOKEN_MANDATORY_LABEL *)mandatory_label_buffer;
|
|
const DWORD sub_authority_count = *GetSidSubAuthorityCount(mandatory_label->Label.Sid);
|
|
const DWORD integrity_level = *GetSidSubAuthority(mandatory_label->Label.Sid, sub_authority_count - 1);
|
|
|
|
CloseHandle(process_token);
|
|
return integrity_level >= SECURITY_MANDATORY_HIGH_RID;
|
|
}
|
|
|
|
CloseHandle(process_token);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
char *loader_getenv(const char *name, const struct loader_instance *inst) {
|
|
int name_utf16_size = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0);
|
|
if (name_utf16_size <= 0) {
|
|
return NULL;
|
|
}
|
|
wchar_t *name_utf16 = (wchar_t *)loader_stack_alloc(name_utf16_size * sizeof(wchar_t));
|
|
if (MultiByteToWideChar(CP_UTF8, 0, name, -1, name_utf16, name_utf16_size) != name_utf16_size) {
|
|
return NULL;
|
|
}
|
|
|
|
DWORD val_size = GetEnvironmentVariableW(name_utf16, NULL, 0);
|
|
// val_size DOES include the null terminator, so for any set variable
|
|
// will always be at least 1. If it's 0, the variable wasn't set.
|
|
if (val_size == 0) {
|
|
return NULL;
|
|
}
|
|
|
|
wchar_t *val = (wchar_t *)loader_stack_alloc(val_size * sizeof(wchar_t));
|
|
if (GetEnvironmentVariableW(name_utf16, val, val_size) != val_size - 1) {
|
|
return NULL;
|
|
}
|
|
|
|
int val_utf8_size = WideCharToMultiByte(CP_UTF8, 0, val, -1, NULL, 0, NULL, NULL);
|
|
if (val_utf8_size <= 0) {
|
|
return NULL;
|
|
}
|
|
char *val_utf8 = (char *)loader_instance_heap_alloc(inst, val_utf8_size * sizeof(char), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
|
|
if (val_utf8 == NULL) {
|
|
return NULL;
|
|
}
|
|
if (WideCharToMultiByte(CP_UTF8, 0, val, -1, val_utf8, val_utf8_size, NULL, NULL) != val_utf8_size) {
|
|
loader_instance_heap_free(inst, val_utf8);
|
|
return NULL;
|
|
}
|
|
return val_utf8;
|
|
}
|
|
|
|
char *loader_secure_getenv(const char *name, const struct loader_instance *inst) {
|
|
if (NULL == name) return NULL;
|
|
#if !defined(LOADER_USE_UNSAFE_FILE_SEARCH)
|
|
if (is_high_integrity()) {
|
|
loader_log(inst, VULKAN_LOADER_INFO_BIT, 0,
|
|
"Loader is running with elevated permissions. Environment variable %s will be ignored", name);
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
return loader_getenv(name, inst);
|
|
}
|
|
|
|
void loader_free_getenv(char *val, const struct loader_instance *inst) { loader_instance_heap_free(inst, (void *)val); }
|
|
|
|
#else
|
|
|
|
#warning \
|
|
"This platform does not support environment variables! If this is not intended, please implement the stubs functions loader_getenv and loader_free_getenv"
|
|
|
|
char *loader_getenv(const char *name, const struct loader_instance *inst) {
|
|
// stub func
|
|
(void)inst;
|
|
(void)name;
|
|
return NULL;
|
|
}
|
|
void loader_free_getenv(char *val, const struct loader_instance *inst) {
|
|
// stub func
|
|
(void)val;
|
|
(void)inst;
|
|
}
|
|
|
|
#endif
|
|
|
|
// Determine the type of filter string based on the contents of it.
|
|
// This will properly check against:
|
|
// - substrings "*string*"
|
|
// - prefixes "string*"
|
|
// - suffixes "*string"
|
|
// - full string names "string"
|
|
// It will also return the correct start and finish to remove any star '*' characters for the actual string compare
|
|
void determine_filter_type(const char *filter_string, enum loader_filter_string_type *filter_type, const char **new_start,
|
|
size_t *new_length) {
|
|
size_t filter_length = strlen(filter_string);
|
|
bool star_begin = false;
|
|
bool star_end = false;
|
|
if ('~' == filter_string[0]) {
|
|
// One of the special identifiers like: ~all~, ~implicit~, or ~explicit~
|
|
*filter_type = FILTER_STRING_SPECIAL;
|
|
*new_start = filter_string;
|
|
*new_length = filter_length;
|
|
} else {
|
|
if ('*' == filter_string[0]) {
|
|
// Only the * means everything
|
|
if (filter_length == 1) {
|
|
*filter_type = FILTER_STRING_SPECIAL;
|
|
*new_start = filter_string;
|
|
*new_length = filter_length;
|
|
} else {
|
|
star_begin = true;
|
|
}
|
|
}
|
|
if ('*' == filter_string[filter_length - 1]) {
|
|
// Not really valid, but just catch this case so if someone accidentally types "**" it will also mean everything
|
|
if (filter_length == 2) {
|
|
*filter_type = FILTER_STRING_SPECIAL;
|
|
*new_start = filter_string;
|
|
*new_length = filter_length;
|
|
} else {
|
|
star_end = true;
|
|
}
|
|
}
|
|
if (star_begin && star_end) {
|
|
*filter_type = FILTER_STRING_SUBSTRING;
|
|
*new_start = &filter_string[1];
|
|
*new_length = filter_length - 2;
|
|
} else if (star_begin) {
|
|
*new_start = &filter_string[1];
|
|
*new_length = filter_length - 1;
|
|
*filter_type = FILTER_STRING_SUFFIX;
|
|
} else if (star_end) {
|
|
*filter_type = FILTER_STRING_PREFIX;
|
|
*new_start = filter_string;
|
|
*new_length = filter_length - 1;
|
|
} else {
|
|
*filter_type = FILTER_STRING_FULLNAME;
|
|
*new_start = filter_string;
|
|
*new_length = filter_length;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Parse the provided filter string provided by the envrionment variable into the appropriate filter
|
|
// struct variable.
|
|
VkResult parse_generic_filter_environment_var(const struct loader_instance *inst, const char *env_var_name,
|
|
struct loader_envvar_filter *filter_struct) {
|
|
VkResult result = VK_SUCCESS;
|
|
memset(filter_struct, 0, sizeof(struct loader_envvar_filter));
|
|
char *parsing_string = NULL;
|
|
char *env_var_value = loader_secure_getenv(env_var_name, inst);
|
|
if (NULL == env_var_value) {
|
|
return result;
|
|
}
|
|
const size_t env_var_len = strlen(env_var_value);
|
|
if (env_var_len == 0) {
|
|
goto out;
|
|
}
|
|
// Allocate a separate string since scan_for_next_comma modifies the original string
|
|
parsing_string = loader_instance_heap_calloc(inst, env_var_len + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
|
|
if (NULL == parsing_string) {
|
|
loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
|
|
"parse_generic_filter_environment_var: Failed to allocate space for parsing env var \'%s\'", env_var_name);
|
|
result = VK_ERROR_OUT_OF_HOST_MEMORY;
|
|
goto out;
|
|
}
|
|
|
|
for (uint32_t iii = 0; iii < env_var_len; ++iii) {
|
|
parsing_string[iii] = (char)tolower(env_var_value[iii]);
|
|
}
|
|
parsing_string[env_var_len] = '\0';
|
|
|
|
char *context = NULL;
|
|
char *token = thread_safe_strtok(parsing_string, ",", &context);
|
|
while (NULL != token) {
|
|
enum loader_filter_string_type cur_filter_type;
|
|
const char *actual_start;
|
|
size_t actual_len;
|
|
determine_filter_type(token, &cur_filter_type, &actual_start, &actual_len);
|
|
if (actual_len > VK_MAX_EXTENSION_NAME_SIZE) {
|
|
loader_strncpy(filter_struct->filters[filter_struct->count].value, VK_MAX_EXTENSION_NAME_SIZE, actual_start,
|
|
VK_MAX_EXTENSION_NAME_SIZE);
|
|
} else {
|
|
loader_strncpy(filter_struct->filters[filter_struct->count].value, VK_MAX_EXTENSION_NAME_SIZE, actual_start,
|
|
actual_len);
|
|
}
|
|
filter_struct->filters[filter_struct->count].length = actual_len;
|
|
filter_struct->filters[filter_struct->count++].type = cur_filter_type;
|
|
if (filter_struct->count >= MAX_ADDITIONAL_FILTERS) {
|
|
break;
|
|
}
|
|
token = thread_safe_strtok(NULL, ",", &context);
|
|
}
|
|
|
|
out:
|
|
|
|
loader_instance_heap_free(inst, parsing_string);
|
|
loader_free_getenv(env_var_value, inst);
|
|
return result;
|
|
}
|
|
|
|
// Parse the disable layer string. The layer disable has some special behavior because we allow it to disable
|
|
// all layers (either with "~all~", "*", or "**"), all implicit layers (with "~implicit~"), and all explicit layers
|
|
// (with "~explicit~"), in addition to the other layer filtering behavior.
|
|
VkResult parse_layers_disable_filter_environment_var(const struct loader_instance *inst,
|
|
struct loader_envvar_disable_layers_filter *disable_struct) {
|
|
VkResult result = VK_SUCCESS;
|
|
memset(disable_struct, 0, sizeof(struct loader_envvar_disable_layers_filter));
|
|
char *parsing_string = NULL;
|
|
char *env_var_value = loader_secure_getenv(VK_LAYERS_DISABLE_ENV_VAR, inst);
|
|
if (NULL == env_var_value) {
|
|
goto out;
|
|
}
|
|
const size_t env_var_len = strlen(env_var_value);
|
|
if (env_var_len == 0) {
|
|
goto out;
|
|
}
|
|
// Allocate a separate string since scan_for_next_comma modifies the original string
|
|
parsing_string = loader_instance_heap_calloc(inst, env_var_len + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
|
|
if (NULL == parsing_string) {
|
|
loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
|
|
"parse_layers_disable_filter_environment_var: Failed to allocate space for parsing env var "
|
|
"\'VK_LAYERS_DISABLE_ENV_VAR\'");
|
|
result = VK_ERROR_OUT_OF_HOST_MEMORY;
|
|
goto out;
|
|
}
|
|
|
|
for (uint32_t iii = 0; iii < env_var_len; ++iii) {
|
|
parsing_string[iii] = (char)tolower(env_var_value[iii]);
|
|
}
|
|
parsing_string[env_var_len] = '\0';
|
|
|
|
char *context = NULL;
|
|
char *token = thread_safe_strtok(parsing_string, ",", &context);
|
|
while (NULL != token) {
|
|
uint32_t cur_count = disable_struct->additional_filters.count;
|
|
enum loader_filter_string_type cur_filter_type;
|
|
const char *actual_start;
|
|
size_t actual_len;
|
|
determine_filter_type(token, &cur_filter_type, &actual_start, &actual_len);
|
|
if (cur_filter_type == FILTER_STRING_SPECIAL) {
|
|
if (!strcmp(VK_LOADER_DISABLE_ALL_LAYERS_VAR_1, token) || !strcmp(VK_LOADER_DISABLE_ALL_LAYERS_VAR_2, token) ||
|
|
!strcmp(VK_LOADER_DISABLE_ALL_LAYERS_VAR_3, token)) {
|
|
disable_struct->disable_all = true;
|
|
} else if (!strcmp(VK_LOADER_DISABLE_IMPLICIT_LAYERS_VAR, token)) {
|
|
disable_struct->disable_all_implicit = true;
|
|
} else if (!strcmp(VK_LOADER_DISABLE_EXPLICIT_LAYERS_VAR, token)) {
|
|
disable_struct->disable_all_explicit = true;
|
|
}
|
|
} else {
|
|
if (actual_len > VK_MAX_EXTENSION_NAME_SIZE) {
|
|
loader_strncpy(disable_struct->additional_filters.filters[cur_count].value, VK_MAX_EXTENSION_NAME_SIZE,
|
|
actual_start, VK_MAX_EXTENSION_NAME_SIZE);
|
|
} else {
|
|
loader_strncpy(disable_struct->additional_filters.filters[cur_count].value, VK_MAX_EXTENSION_NAME_SIZE,
|
|
actual_start, actual_len);
|
|
}
|
|
disable_struct->additional_filters.filters[cur_count].length = actual_len;
|
|
disable_struct->additional_filters.filters[cur_count].type = cur_filter_type;
|
|
disable_struct->additional_filters.count++;
|
|
if (disable_struct->additional_filters.count >= MAX_ADDITIONAL_FILTERS) {
|
|
break;
|
|
}
|
|
}
|
|
token = thread_safe_strtok(NULL, ",", &context);
|
|
}
|
|
out:
|
|
loader_instance_heap_free(inst, parsing_string);
|
|
loader_free_getenv(env_var_value, inst);
|
|
return result;
|
|
}
|
|
|
|
// Parses the filter environment variables to determine if we have any special behavior
|
|
VkResult parse_layer_environment_var_filters(const struct loader_instance *inst, struct loader_envvar_all_filters *layer_filters) {
|
|
VkResult res = parse_generic_filter_environment_var(inst, VK_LAYERS_ENABLE_ENV_VAR, &layer_filters->enable_filter);
|
|
if (VK_SUCCESS != res) {
|
|
return res;
|
|
}
|
|
res = parse_layers_disable_filter_environment_var(inst, &layer_filters->disable_filter);
|
|
if (VK_SUCCESS != res) {
|
|
return res;
|
|
}
|
|
res = parse_generic_filter_environment_var(inst, VK_LAYERS_ALLOW_ENV_VAR, &layer_filters->allow_filter);
|
|
if (VK_SUCCESS != res) {
|
|
return res;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
// Check to see if the provided layer name matches any of the filter strings.
|
|
// This will properly check against:
|
|
// - substrings "*string*"
|
|
// - prefixes "string*"
|
|
// - suffixes "*string"
|
|
// - full string names "string"
|
|
bool check_name_matches_filter_environment_var(const char *name, const struct loader_envvar_filter *filter_struct) {
|
|
bool ret_value = false;
|
|
const size_t name_len = strlen(name);
|
|
char lower_name[VK_MAX_EXTENSION_NAME_SIZE];
|
|
for (uint32_t iii = 0; iii < name_len; ++iii) {
|
|
lower_name[iii] = (char)tolower(name[iii]);
|
|
}
|
|
lower_name[name_len] = '\0';
|
|
for (uint32_t filt = 0; filt < filter_struct->count; ++filt) {
|
|
// Check if the filter name is longer (this is with all special characters removed), and if it is
|
|
// continue since it can't match.
|
|
if (filter_struct->filters[filt].length > name_len) {
|
|
continue;
|
|
}
|
|
switch (filter_struct->filters[filt].type) {
|
|
case FILTER_STRING_SPECIAL:
|
|
if (!strcmp(VK_LOADER_DISABLE_ALL_LAYERS_VAR_1, filter_struct->filters[filt].value) ||
|
|
!strcmp(VK_LOADER_DISABLE_ALL_LAYERS_VAR_2, filter_struct->filters[filt].value) ||
|
|
!strcmp(VK_LOADER_DISABLE_ALL_LAYERS_VAR_3, filter_struct->filters[filt].value)) {
|
|
ret_value = true;
|
|
}
|
|
break;
|
|
|
|
case FILTER_STRING_SUBSTRING:
|
|
if (NULL != strstr(lower_name, filter_struct->filters[filt].value)) {
|
|
ret_value = true;
|
|
}
|
|
break;
|
|
|
|
case FILTER_STRING_SUFFIX:
|
|
if (0 == strncmp(lower_name + name_len - filter_struct->filters[filt].length, filter_struct->filters[filt].value,
|
|
filter_struct->filters[filt].length)) {
|
|
ret_value = true;
|
|
}
|
|
break;
|
|
|
|
case FILTER_STRING_PREFIX:
|
|
if (0 == strncmp(lower_name, filter_struct->filters[filt].value, filter_struct->filters[filt].length)) {
|
|
ret_value = true;
|
|
}
|
|
break;
|
|
|
|
case FILTER_STRING_FULLNAME:
|
|
if (0 == strncmp(lower_name, filter_struct->filters[filt].value, name_len)) {
|
|
ret_value = true;
|
|
}
|
|
break;
|
|
}
|
|
if (ret_value) {
|
|
break;
|
|
}
|
|
}
|
|
return ret_value;
|
|
}
|
|
|
|
// Get the layer name(s) from the env_name environment variable. If layer is found in
|
|
// search_list then add it to layer_list. But only add it to layer_list if type_flags matches.
|
|
VkResult loader_add_environment_layers(struct loader_instance *inst, const enum layer_type_flags type_flags,
|
|
const struct loader_envvar_all_filters *filters,
|
|
struct loader_pointer_layer_list *target_list,
|
|
struct loader_pointer_layer_list *expanded_target_list,
|
|
const struct loader_layer_list *source_list) {
|
|
VkResult res = VK_SUCCESS;
|
|
char *layer_env = loader_getenv(ENABLED_LAYERS_ENV, inst);
|
|
|
|
// If the layer environment variable is present (i.e. VK_INSTANCE_LAYERS), we will always add it to the layer list.
|
|
if (layer_env != NULL) {
|
|
size_t layer_env_len = strlen(layer_env) + 1;
|
|
char *name = loader_stack_alloc(layer_env_len);
|
|
if (name != NULL) {
|
|
loader_strncpy(name, layer_env_len, layer_env, layer_env_len);
|
|
|
|
loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0, "env var \'%s\' defined and adding layers \"%s\"",
|
|
ENABLED_LAYERS_ENV, name);
|
|
|
|
// First look for the old-fashion layers forced on with VK_INSTANCE_LAYERS
|
|
while (name && *name) {
|
|
char *next = loader_get_next_path(name);
|
|
|
|
if (strlen(name) > 0) {
|
|
bool found = false;
|
|
for (uint32_t i = 0; i < source_list->count; i++) {
|
|
struct loader_layer_properties *source_prop = &source_list->list[i];
|
|
|
|
if (0 == strcmp(name, source_prop->info.layerName)) {
|
|
found = true;
|
|
// Only add it if it doesn't already appear in the layer list
|
|
if (!loader_find_layer_name_in_list(source_prop->info.layerName, target_list)) {
|
|
if (0 == (source_prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) {
|
|
res = loader_add_layer_properties_to_list(inst, target_list, source_prop);
|
|
if (res == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
|
|
res = loader_add_layer_properties_to_list(inst, expanded_target_list, source_prop);
|
|
if (res == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
|
|
} else {
|
|
res = loader_add_meta_layer(inst, filters, source_prop, target_list, expanded_target_list,
|
|
source_list, NULL);
|
|
if (res == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!found) {
|
|
loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_LAYER_BIT, 0,
|
|
"Layer \"%s\" was not found but was requested by env var VK_INSTANCE_LAYERS!", name);
|
|
}
|
|
}
|
|
name = next;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Loop through all the layers and check the enable/disable filters
|
|
for (uint32_t i = 0; i < source_list->count; i++) {
|
|
struct loader_layer_properties *source_prop = &source_list->list[i];
|
|
|
|
// If it doesn't match the type, or the name isn't what we're looking for, just continue
|
|
if ((source_prop->type_flags & type_flags) != type_flags) {
|
|
continue;
|
|
}
|
|
|
|
// We found a layer we're interested in, but has it been disabled...
|
|
bool adding = true;
|
|
bool is_implicit = (0 == (source_prop->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER));
|
|
bool disabled_by_type =
|
|
(is_implicit) ? (filters->disable_filter.disable_all_implicit) : (filters->disable_filter.disable_all_explicit);
|
|
if ((filters->disable_filter.disable_all || disabled_by_type ||
|
|
check_name_matches_filter_environment_var(source_prop->info.layerName, &filters->disable_filter.additional_filters)) &&
|
|
!check_name_matches_filter_environment_var(source_prop->info.layerName, &filters->allow_filter)) {
|
|
loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
|
|
"Layer \"%s\" ignored because it has been disabled by env var \'%s\'", source_prop->info.layerName,
|
|
VK_LAYERS_DISABLE_ENV_VAR);
|
|
adding = false;
|
|
}
|
|
|
|
// If we are supposed to filter through all layers, we need to compare the layer name against the filter.
|
|
// This can override the disable above, so we want to do it second.
|
|
// Also make sure the layer isn't already in the output_list, skip adding it if it is.
|
|
if (check_name_matches_filter_environment_var(source_prop->info.layerName, &filters->enable_filter) &&
|
|
!loader_find_layer_name_in_list(source_prop->info.layerName, target_list)) {
|
|
adding = true;
|
|
// Only way is_substring is true is if there are enable variables. If that's the case, and we're past the
|
|
// above, we should indicate that it was forced on in this way.
|
|
loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_LAYER_BIT, 0,
|
|
"Layer \"%s\" forced enabled due to env var \'%s\'", source_prop->info.layerName, VK_LAYERS_ENABLE_ENV_VAR);
|
|
} else {
|
|
adding = false;
|
|
}
|
|
|
|
if (!adding) {
|
|
continue;
|
|
}
|
|
|
|
// If not a meta-layer, simply add it.
|
|
if (0 == (source_prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) {
|
|
res = loader_add_layer_properties_to_list(inst, target_list, source_prop);
|
|
if (res == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
|
|
res = loader_add_layer_properties_to_list(inst, expanded_target_list, source_prop);
|
|
if (res == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
|
|
} else {
|
|
res = loader_add_meta_layer(inst, filters, source_prop, target_list, expanded_target_list, source_list, NULL);
|
|
if (res == VK_ERROR_OUT_OF_HOST_MEMORY) goto out;
|
|
}
|
|
}
|
|
|
|
out:
|
|
|
|
if (layer_env != NULL) {
|
|
loader_free_getenv(layer_env, inst);
|
|
}
|
|
|
|
return res;
|
|
}
|