aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Zulauf <jzulauf@LunarG.com>2018-04-16 11:00:43 -0600
committerJohn Zulauf <32470354+jzulauf-lunarg@users.noreply.github.com>2018-04-25 15:15:22 -0600
commit4262c239e5021777a97d164583475864207af262 (patch)
tree6d9d92044fa86f9140952964e6ba34e363cbde59
parent860fd0db693aa260b01fcefce4ac5804413d068a (diff)
downloadusermoji-4262c239e5021777a97d164583475864207af262.tar.xz
layers: Implement extension dependency validation
Add CreateInstance and CreateDevice validation checks for extension dependencies. VALIDATION_ERROR_1fc00ad6 VUID-vkCreateDevice-ppEnabledExtensionNames-01387 VALIDATION_ERROR_21200ad8 VUID-vkCreateInstance-ppEnabledExtensionNames-01388 Change-Id: Ia78f15494f10a1eca6a2a33e3a22d769b5d38785
-rw-r--r--layers/parameter_validation_utils.cpp134
-rw-r--r--layers/vk_validation_error_database.txt4
2 files changed, 96 insertions, 42 deletions
diff --git a/layers/parameter_validation_utils.cpp b/layers/parameter_validation_utils.cpp
index 6adb003e..2f467b53 100644
--- a/layers/parameter_validation_utils.cpp
+++ b/layers/parameter_validation_utils.cpp
@@ -191,6 +191,68 @@ static bool ValidateQueueFamilies(layer_data *device_data, uint32_t queue_family
return skip;
}
+static bool validate_api_version(const instance_layer_data *instance_data, uint32_t api_version, uint32_t effective_api_version) {
+ bool skip = false;
+ uint32_t api_version_nopatch = VK_MAKE_VERSION(VK_VERSION_MAJOR(api_version), VK_VERSION_MINOR(api_version), 0);
+ if (api_version_nopatch != effective_api_version) {
+ if (api_version_nopatch < VK_API_VERSION_1_0) {
+ skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT,
+ HandleToUint64(instance_data->instance), VALIDATION_ERROR_UNDEFINED,
+ "Invalid CreateInstance->pCreateInfo->pApplicationInfo.apiVersion number (0x%08x). "
+ "Using VK_API_VERSION_%" PRIu32 "_%" PRIu32 ".",
+ api_version, VK_VERSION_MAJOR(effective_api_version), VK_VERSION_MINOR(effective_api_version));
+ } else {
+ skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT,
+ HandleToUint64(instance_data->instance), VALIDATION_ERROR_UNDEFINED,
+ "Unrecognized CreateInstance->pCreateInfo->pApplicationInfo.apiVersion number (0x%08x). "
+ "Assuming VK_API_VERSION_%" PRIu32 "_%" PRIu32 ".",
+ api_version, VK_VERSION_MAJOR(effective_api_version), VK_VERSION_MINOR(effective_api_version));
+ }
+ }
+ return skip;
+}
+
+template <typename ExtensionState>
+static bool validate_extension_reqs(const instance_layer_data *instance_data, const ExtensionState &extensions,
+ UNIQUE_VALIDATION_ERROR_CODE vuid, const char *extension_type, const char *extension_name) {
+ bool skip = false;
+ if (!extension_name) {
+ return skip; // Robust to invalid char *
+ }
+ auto info = ExtensionState::get_info(extension_name);
+
+ if (!info.state) {
+ return skip; // Unknown extensions cannot be checked so report OK
+ }
+
+ // Check agains the reqs list in the info
+ std::vector<const char *> missing;
+ for (const auto &req : info.requires) {
+ if (!(extensions.*(req.enabled))) {
+ missing.push_back(req.name);
+ }
+ }
+
+ // Report any missing requirements
+ if (missing.size()) {
+ std::string missing_joined_list = string_join(", ", missing);
+ skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT,
+ HandleToUint64(instance_data->instance), vuid, "Missing required extensions for %s extension %s, %s.",
+ extension_type, extension_name, missing_joined_list.c_str());
+ }
+ return skip;
+}
+
+bool validate_instance_extensions(const instance_layer_data *instance_data, const VkInstanceCreateInfo *pCreateInfo) {
+ bool skip = false;
+ for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
+ skip |= validate_extension_reqs(instance_data, instance_data->extensions, VALIDATION_ERROR_21200ad8, "instance",
+ pCreateInfo->ppEnabledExtensionNames[i]);
+ }
+
+ return skip;
+}
+
VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
VkInstance *pInstance) {
VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
@@ -265,25 +327,11 @@ VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance(const VkInstanceCreateInfo *pCre
uint32_t effective_api_version = my_instance_data->extensions.InitFromInstanceCreateInfo(api_version, pCreateInfo);
- uint32_t api_version_nopatch = VK_MAKE_VERSION(VK_VERSION_MAJOR(api_version), VK_VERSION_MINOR(api_version), 0);
- if (api_version_nopatch != effective_api_version) {
- const char *effective_api_string =
- (effective_api_version == VK_API_VERSION_1_0) ? "VK_API_VERSION_1_0" : "VK_API_VERSION_1_1";
- if (api_version_nopatch < VK_API_VERSION_1_0) {
- log_msg(my_instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
- VALIDATION_ERROR_UNDEFINED,
- "Invalid CreateInstance->pCreateInfo->pApplicationInfo.apiVersion number (0x%08x). Using %s.\n",
- api_version, effective_api_string);
- } else {
- log_msg(my_instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
- VALIDATION_ERROR_UNDEFINED,
- "Unrecognized CreateInstance->pCreateInfo->pApplicationInfo.apiVersion number (0x%08x). Assuming %s.\n",
- api_version, effective_api_string);
- }
- }
-
// Ordinarily we'd check these before calling down the chain, but none of the layer support is in place until now, if we
// survive we can report the issue now.
+ validate_api_version(my_instance_data, api_version, effective_api_version);
+ validate_instance_extensions(my_instance_data, pCreateInfo);
+
parameter_validation_vkCreateInstance(*pInstance, pCreateInfo, pAllocator, pInstance);
if (pCreateInfo->pApplicationInfo) {
@@ -431,9 +479,19 @@ VKAPI_ATTR void VKAPI_CALL vkDestroyDebugUtilsMessengerEXT(VkInstance instance,
}
}
+template <typename ExtensionState>
+static bool extension_state_by_name(const ExtensionState &extensions, const char *extension_name) {
+ if (!extension_name) return false; // null strings specify nothing
+ auto info = ExtensionState::get_info(extension_name);
+ bool state = info.state ? extensions.*(info.state) : false; // unknown extensions can't be enabled in extension struct
+ return state;
+}
+
static bool ValidateDeviceCreateInfo(instance_layer_data *instance_data, VkPhysicalDevice physicalDevice,
- const VkDeviceCreateInfo *pCreateInfo) {
+ const VkDeviceCreateInfo *pCreateInfo, const DeviceExtensions &extensions) {
bool skip = false;
+ bool maint1 = false;
+ bool negative_viewport = false;
if ((pCreateInfo->enabledLayerCount > 0) && (pCreateInfo->ppEnabledLayerNames != NULL)) {
for (size_t i = 0; i < pCreateInfo->enabledLayerCount; i++) {
@@ -442,16 +500,15 @@ static bool ValidateDeviceCreateInfo(instance_layer_data *instance_data, VkPhysi
}
}
- bool maint1 = false;
- bool negative_viewport = false;
-
if ((pCreateInfo->enabledExtensionCount > 0) && (pCreateInfo->ppEnabledExtensionNames != NULL)) {
+ maint1 = extension_state_by_name(extensions, VK_KHR_MAINTENANCE1_EXTENSION_NAME);
+ negative_viewport = extension_state_by_name(extensions, VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_EXTENSION_NAME);
+
for (size_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
skip |= validate_string(instance_data->report_data, "vkCreateDevice", "pCreateInfo->ppEnabledExtensionNames",
pCreateInfo->ppEnabledExtensionNames[i]);
- if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_MAINTENANCE1_EXTENSION_NAME) == 0) maint1 = true;
- if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_EXTENSION_NAME) == 0)
- negative_viewport = true;
+ skip |= validate_extension_reqs(instance_data, extensions, VALIDATION_ERROR_1fc00ad6, "device",
+ pCreateInfo->ppEnabledExtensionNames[i]);
}
}
@@ -526,11 +583,21 @@ VKAPI_ATTR VkResult VKAPI_CALL vkCreateDevice(VkPhysicalDevice physicalDevice, c
bool skip = false;
auto my_instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
assert(my_instance_data != nullptr);
+
+ // Query and save physical device limits for this device, needed for validation
+ VkPhysicalDeviceProperties device_properties = {};
+ my_instance_data->dispatch_table.GetPhysicalDeviceProperties(physicalDevice, &device_properties);
+
+ // Set up the extension structure also for validation.
+ DeviceExtensions extensions;
+ uint32_t api_version =
+ extensions.InitFromDeviceCreateInfo(&my_instance_data->extensions, device_properties.apiVersion, pCreateInfo);
+
std::unique_lock<std::mutex> lock(global_lock);
skip |= parameter_validation_vkCreateDevice(physicalDevice, pCreateInfo, pAllocator, pDevice);
- if (pCreateInfo != NULL) skip |= ValidateDeviceCreateInfo(my_instance_data, physicalDevice, pCreateInfo);
+ if (pCreateInfo != NULL) skip |= ValidateDeviceCreateInfo(my_instance_data, physicalDevice, pCreateInfo, extensions);
if (!skip) {
VkLayerDeviceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
@@ -560,21 +627,8 @@ VKAPI_ATTR VkResult VKAPI_CALL vkCreateDevice(VkPhysicalDevice physicalDevice, c
my_device_data->report_data = layer_debug_utils_create_device(my_instance_data->report_data, *pDevice);
layer_init_device_dispatch_table(*pDevice, &my_device_data->dispatch_table, fpGetDeviceProcAddr);
- // Query and save physical device limits for this device
- VkPhysicalDeviceProperties device_properties = {};
- my_instance_data->dispatch_table.GetPhysicalDeviceProperties(physicalDevice, &device_properties);
-
- my_device_data->api_version = my_device_data->extensions.InitFromDeviceCreateInfo(
- &my_instance_data->extensions, device_properties.apiVersion, pCreateInfo);
-
- uint32_t specified_api_version = device_properties.apiVersion & ~VK_VERSION_PATCH(~0);
- if (!(specified_api_version == VK_API_VERSION_1_0) && !(specified_api_version == VK_API_VERSION_1_1)) {
- LOGCONSOLE(
- "Warning: Unrecognized CreateInstance->pCreateInfo->pApplicationInfo.apiVersion number -- (0x%8x) assuming "
- "%s.\n",
- device_properties.apiVersion,
- (my_device_data->api_version == VK_API_VERSION_1_0) ? "VK_API_VERSION_1_0" : "VK_API_VERSION_1_1");
- }
+ my_device_data->api_version = api_version;
+ my_device_data->extensions = extensions;
// Store createdevice data
if ((pCreateInfo != nullptr) && (pCreateInfo->pQueueCreateInfos != nullptr)) {
diff --git a/layers/vk_validation_error_database.txt b/layers/vk_validation_error_database.txt
index 96c99f80..dd2a09e5 100644
--- a/layers/vk_validation_error_database.txt
+++ b/layers/vk_validation_error_database.txt
@@ -2663,7 +2663,7 @@ VALIDATION_ERROR_1fa05601~^~Y~^~Unknown~^~vkCreateDescriptorUpdateTemplate~^~VUI
VALIDATION_ERROR_1fa0ec01~^~N~^~Unknown~^~vkCreateDescriptorUpdateTemplate~^~VUID-vkCreateDescriptorUpdateTemplate-pAllocator-parameter~^~(VK_VERSION_1_1,VK_KHR_descriptor_update_template)~^~The spec valid usage text states 'If pAllocator is not NULL, pAllocator must be a valid pointer to a valid VkAllocationCallbacks structure' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/html/vkspec.html#VUID-vkCreateDescriptorUpdateTemplate-pAllocator-parameter)~^~implicit
VALIDATION_ERROR_1fa11e01~^~N~^~Unknown~^~vkCreateDescriptorUpdateTemplate~^~VUID-vkCreateDescriptorUpdateTemplate-pCreateInfo-parameter~^~(VK_VERSION_1_1,VK_KHR_descriptor_update_template)~^~The spec valid usage text states 'pCreateInfo must be a valid pointer to a valid VkDescriptorUpdateTemplateCreateInfo structure' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/html/vkspec.html#VUID-vkCreateDescriptorUpdateTemplate-pCreateInfo-parameter)~^~implicit
VALIDATION_ERROR_1fa13401~^~Y~^~Unknown~^~vkCreateDescriptorUpdateTemplate~^~VUID-vkCreateDescriptorUpdateTemplate-pDescriptorUpdateTemplate-parameter~^~(VK_VERSION_1_1,VK_KHR_descriptor_update_template)~^~The spec valid usage text states 'pDescriptorUpdateTemplate must be a valid pointer to a VkDescriptorUpdateTemplate handle' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/html/vkspec.html#VUID-vkCreateDescriptorUpdateTemplate-pDescriptorUpdateTemplate-parameter)~^~implicit
-VALIDATION_ERROR_1fc00ad6~^~N~^~None~^~vkCreateDevice~^~VUID-vkCreateDevice-ppEnabledExtensionNames-01387~^~core~^~The spec valid usage text states 'All required extensions for each extension in the VkDeviceCreateInfo::ppEnabledExtensionNames list must also be present in that list.' (https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#VUID-vkCreateDevice-ppEnabledExtensionNames-01387)~^~
+VALIDATION_ERROR_1fc00ad6~^~Y~^~None~^~vkCreateDevice~^~VUID-vkCreateDevice-ppEnabledExtensionNames-01387~^~core~^~The spec valid usage text states 'All required extensions for each extension in the VkDeviceCreateInfo::ppEnabledExtensionNames list must also be present in that list.' (https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#VUID-vkCreateDevice-ppEnabledExtensionNames-01387)~^~
VALIDATION_ERROR_1fc0ec01~^~N~^~Unknown~^~vkCreateDevice~^~VUID-vkCreateDevice-pAllocator-parameter~^~core~^~The spec valid usage text states 'If pAllocator is not NULL, pAllocator must be a valid pointer to a valid VkAllocationCallbacks structure' (https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#VUID-vkCreateDevice-pAllocator-parameter)~^~implicit
VALIDATION_ERROR_1fc11e01~^~N~^~Unknown~^~vkCreateDevice~^~VUID-vkCreateDevice-pCreateInfo-parameter~^~core~^~The spec valid usage text states 'pCreateInfo must be a valid pointer to a valid VkDeviceCreateInfo structure' (https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#VUID-vkCreateDevice-pCreateInfo-parameter)~^~implicit
VALIDATION_ERROR_1fc13801~^~Y~^~Unknown~^~vkCreateDevice~^~VUID-vkCreateDevice-pDevice-parameter~^~core~^~The spec valid usage text states 'pDevice must be a valid pointer to a VkDevice handle' (https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#VUID-vkCreateDevice-pDevice-parameter)~^~implicit
@@ -2715,7 +2715,7 @@ VALIDATION_ERROR_21005601~^~Y~^~Unknown~^~vkCreateIndirectCommandsLayoutNVX~^~VU
VALIDATION_ERROR_2100ec01~^~N~^~Unknown~^~vkCreateIndirectCommandsLayoutNVX~^~VUID-vkCreateIndirectCommandsLayoutNVX-pAllocator-parameter~^~(VK_NVX_device_generated_commands)~^~The spec valid usage text states 'If pAllocator is not NULL, pAllocator must be a valid pointer to a valid VkAllocationCallbacks structure' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/html/vkspec.html#VUID-vkCreateIndirectCommandsLayoutNVX-pAllocator-parameter)~^~implicit
VALIDATION_ERROR_21011e01~^~N~^~Unknown~^~vkCreateIndirectCommandsLayoutNVX~^~VUID-vkCreateIndirectCommandsLayoutNVX-pCreateInfo-parameter~^~(VK_NVX_device_generated_commands)~^~The spec valid usage text states 'pCreateInfo must be a valid pointer to a valid VkIndirectCommandsLayoutCreateInfoNVX structure' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/html/vkspec.html#VUID-vkCreateIndirectCommandsLayoutNVX-pCreateInfo-parameter)~^~implicit
VALIDATION_ERROR_21019201~^~Y~^~Unknown~^~vkCreateIndirectCommandsLayoutNVX~^~VUID-vkCreateIndirectCommandsLayoutNVX-pIndirectCommandsLayout-parameter~^~(VK_NVX_device_generated_commands)~^~The spec valid usage text states 'pIndirectCommandsLayout must be a valid pointer to a VkIndirectCommandsLayoutNVX handle' (https://www.khronos.org/registry/vulkan/specs/1.0-extensions/html/vkspec.html#VUID-vkCreateIndirectCommandsLayoutNVX-pIndirectCommandsLayout-parameter)~^~implicit
-VALIDATION_ERROR_21200ad8~^~N~^~None~^~vkCreateInstance~^~VUID-vkCreateInstance-ppEnabledExtensionNames-01388~^~core~^~The spec valid usage text states 'All required extensions for each extension in the VkInstanceCreateInfo::ppEnabledExtensionNames list must also be present in that list.' (https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#VUID-vkCreateInstance-ppEnabledExtensionNames-01388)~^~
+VALIDATION_ERROR_21200ad8~^~Y~^~None~^~vkCreateInstance~^~VUID-vkCreateInstance-ppEnabledExtensionNames-01388~^~core~^~The spec valid usage text states 'All required extensions for each extension in the VkInstanceCreateInfo::ppEnabledExtensionNames list must also be present in that list.' (https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#VUID-vkCreateInstance-ppEnabledExtensionNames-01388)~^~
VALIDATION_ERROR_2120ec01~^~N~^~Unknown~^~vkCreateInstance~^~VUID-vkCreateInstance-pAllocator-parameter~^~core~^~The spec valid usage text states 'If pAllocator is not NULL, pAllocator must be a valid pointer to a valid VkAllocationCallbacks structure' (https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#VUID-vkCreateInstance-pAllocator-parameter)~^~implicit, A bad pointer can cause the loader to seg fault. Unfortunately, the validity of the allocator is hard to determine. The structure does not contain an sType and is not created by the Vulkan API. We could try to catch an access violation exception but the loader is written in C, which does not support exceptions. It's not clear if this could be validated in a layer before loader consumption. We could also try to install a signal handler in the loader.
VALIDATION_ERROR_21211e01~^~N~^~Unknown~^~vkCreateInstance~^~VUID-vkCreateInstance-pCreateInfo-parameter~^~core~^~The spec valid usage text states 'pCreateInfo must be a valid pointer to a valid VkInstanceCreateInfo structure' (https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#VUID-vkCreateInstance-pCreateInfo-parameter)~^~implicit, We check the sType correctly, but this can cause the loader to seg fault when pCreateInfo is a nullptr.
VALIDATION_ERROR_21219c01~^~Y~^~Unknown~^~vkCreateInstance~^~VUID-vkCreateInstance-pInstance-parameter~^~core~^~The spec valid usage text states 'pInstance must be a valid pointer to a VkInstance handle' (https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#VUID-vkCreateInstance-pInstance-parameter)~^~implicit, How should this be validated? Aside from insidious type-casting, the type will be validated by the compiler. The instance has not been created yet and will likely have no presence in the layers.