blob: d302ab69a316889ea446e62cabedb383a0c38b28 [file] [log] [blame]
/*
* Copyright (c) 2015-2023 The Khronos Group Inc.
* Copyright (c) 2015-2023 Valve Corporation
* Copyright (c) 2015-2023 LunarG, Inc.
* Copyright (c) 2015-2023 Google, Inc.
* Modifications Copyright (C) 2020-2021 Advanced Micro Devices, Inc. All rights reserved.
*
* 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
*/
#include "utils/cast_utils.h"
#include "error_message/validation_error_enums.h"
#include "generated/enum_flag_bits.h"
#include "../framework/layer_validation_tests.h"
#include "utils/vk_layer_utils.h"
#include "generated/vk_validation_error_messages.h"
class MessageIdFilter {
public:
MessageIdFilter(const char *filter_string) {
local_string = filter_string;
filter_string_value.arrayString.pCharArray = local_string.data();
filter_string_value.arrayString.count = local_string.size();
strncpy(filter_setting_val.name, "message_id_filter", sizeof(filter_setting_val.name));
filter_setting_val.type = VK_LAYER_SETTING_VALUE_TYPE_STRING_ARRAY_EXT;
filter_setting_val.data = filter_string_value;
filter_setting = {VK_STRUCTURE_TYPE_INSTANCE_LAYER_SETTINGS_EXT, nullptr, 1, &filter_setting_val};
}
VkLayerSettingsEXT *pnext{&filter_setting};
private:
VkLayerSettingValueDataEXT filter_string_value{};
VkLayerSettingValueEXT filter_setting_val;
VkLayerSettingsEXT filter_setting;
std::string local_string;
};
class CustomStypeList {
public:
CustomStypeList(const char *stype_id_string) {
local_string = stype_id_string;
custom_stype_value.arrayString.pCharArray = local_string.data();
custom_stype_value.arrayString.count = local_string.size();
strncpy(custom_stype_setting_val.name, "custom_stype_list", sizeof(custom_stype_setting_val.name));
custom_stype_setting_val.type = VK_LAYER_SETTING_VALUE_TYPE_STRING_ARRAY_EXT;
custom_stype_setting_val.data = custom_stype_value;
custom_stype_setting = {VK_STRUCTURE_TYPE_INSTANCE_LAYER_SETTINGS_EXT, nullptr, 1, &custom_stype_setting_val};
}
CustomStypeList(const std::vector<uint32_t> &stype_id_array) {
local_vector = stype_id_array;
custom_stype_value.arrayInt32.pInt32Array = local_vector.data();
custom_stype_value.arrayInt32.count = local_vector.size();
strncpy(custom_stype_setting_val.name, "custom_stype_list", sizeof(custom_stype_setting_val.name));
custom_stype_setting_val.type = VK_LAYER_SETTING_VALUE_TYPE_UINT32_ARRAY_EXT;
custom_stype_setting_val.data = custom_stype_value;
custom_stype_setting = {VK_STRUCTURE_TYPE_INSTANCE_LAYER_SETTINGS_EXT, nullptr, 1, &custom_stype_setting_val};
}
VkLayerSettingsEXT *pnext{&custom_stype_setting};
private:
VkLayerSettingValueDataEXT custom_stype_value{};
VkLayerSettingValueEXT custom_stype_setting_val;
VkLayerSettingsEXT custom_stype_setting;
std::string local_string;
std::vector<uint32_t> local_vector;
};
class DuplicateMsgLimit {
public:
DuplicateMsgLimit(const uint32_t limit) {
limit_value.value32 = limit;
strncpy(limit_setting_val.name, "duplicate_message_limit", sizeof(limit_setting_val.name));
limit_setting_val.type = VK_LAYER_SETTING_VALUE_TYPE_UINT32_EXT;
limit_setting_val.data = limit_value;
limit_setting = {VK_STRUCTURE_TYPE_INSTANCE_LAYER_SETTINGS_EXT, nullptr, 1, &limit_setting_val};
}
VkLayerSettingsEXT *pnext{&limit_setting};
private:
VkLayerSettingValueDataEXT limit_value{};
VkLayerSettingValueEXT limit_setting_val;
VkLayerSettingsEXT limit_setting;
};
TEST_F(VkLayerTest, VersionCheckPromotedAPIs) {
TEST_DESCRIPTION("Validate that promoted APIs are not valid in old versions.");
SetTargetApiVersion(VK_API_VERSION_1_0);
ASSERT_NO_FATAL_FAILURE(Init());
// TODO - Currently not working on MockICD with Profiles using 1.0
// Seems API version is not being passed through correctly
if (IsPlatform(kMockICD)) {
GTEST_SKIP() << "Test not supported by MockICD";
}
PFN_vkGetPhysicalDeviceProperties2 vkGetPhysicalDeviceProperties2 =
(PFN_vkGetPhysicalDeviceProperties2)vk::GetInstanceProcAddr(instance(), "vkGetPhysicalDeviceProperties2");
VkPhysicalDeviceProperties2 phys_dev_props_2 = LvlInitStruct<VkPhysicalDeviceProperties2>();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "UNASSIGNED-API-Version-Violation");
vkGetPhysicalDeviceProperties2(gpu(), &phys_dev_props_2);
m_errorMonitor->VerifyFound();
}
TEST_F(VkLayerTest, UnsupportedPnextApiVersion) {
TEST_DESCRIPTION("Validate that newer pnext structs are not valid for old Vulkan versions.");
SetTargetApiVersion(VK_API_VERSION_1_1);
ASSERT_NO_FATAL_FAILURE(Init());
if (IsPlatform(kNexusPlayer)) {
GTEST_SKIP() << "This test should not run on Nexus Player";
}
auto phys_dev_props_2 = LvlInitStruct<VkPhysicalDeviceProperties2>();
auto bad_version_1_1_struct = LvlInitStruct<VkPhysicalDeviceVulkan12Properties>();
phys_dev_props_2.pNext = &bad_version_1_1_struct;
// VkPhysDevVulkan12Props was introduced in 1.2, so try adding it to a 1.1 pNext chain
if (DeviceValidationVersion() >= VK_API_VERSION_1_1) {
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPhysicalDeviceProperties2-pNext-pNext");
vk::GetPhysicalDeviceProperties2(gpu(), &phys_dev_props_2);
m_errorMonitor->VerifyFound();
}
// 1.1 context, VK_KHR_depth_stencil_resolve is NOT enabled, but using its struct is valid
if (DeviceExtensionSupported(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME)) {
auto unenabled_device_ext_struct = LvlInitStruct<VkPhysicalDeviceDepthStencilResolveProperties>();
phys_dev_props_2.pNext = &unenabled_device_ext_struct;
if (DeviceValidationVersion() >= VK_API_VERSION_1_1) {
vk::GetPhysicalDeviceProperties2(gpu(), &phys_dev_props_2);
} else {
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "UNASSIGNED-API-Version-Violation");
vk::GetPhysicalDeviceProperties2(gpu(), &phys_dev_props_2);
m_errorMonitor->VerifyFound();
}
}
}
TEST_F(VkLayerTest, PrivateDataExtTest) {
TEST_DESCRIPTION("Test private data extension use.");
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_PRIVATE_DATA_EXTENSION_NAME);
ASSERT_NO_FATAL_FAILURE(InitFramework());
if (IsPlatform(kMockICD)) {
GTEST_SKIP() << "Test not supported by MockICD";
}
if (!AreRequiredExtensionsEnabled()) {
GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported";
}
auto private_data_features = LvlInitStruct<VkPhysicalDevicePrivateDataFeaturesEXT>();
auto features2 = GetPhysicalDeviceFeatures2(private_data_features);
if (private_data_features.privateData == VK_FALSE) {
GTEST_SKIP() << "privateData feature is not supported";
}
ASSERT_NO_FATAL_FAILURE(InitState(nullptr, &features2));
PFN_vkDestroyPrivateDataSlotEXT pfn_vkDestroyPrivateDataSlotEXT =
(PFN_vkDestroyPrivateDataSlotEXT)vk::GetDeviceProcAddr(m_device->handle(), "vkDestroyPrivateDataSlotEXT");
PFN_vkCreatePrivateDataSlotEXT pfn_vkCreatePrivateDataSlotEXT =
(PFN_vkCreatePrivateDataSlotEXT)vk::GetDeviceProcAddr(m_device->handle(), "vkCreatePrivateDataSlotEXT");
PFN_vkGetPrivateDataEXT pfn_vkGetPrivateDataEXT =
(PFN_vkGetPrivateDataEXT)vk::GetDeviceProcAddr(m_device->handle(), "vkGetPrivateDataEXT");
PFN_vkSetPrivateDataEXT pfn_vkSetPrivateDataEXT =
(PFN_vkSetPrivateDataEXT)vk::GetDeviceProcAddr(m_device->handle(), "vkSetPrivateDataEXT");
VkPrivateDataSlotEXT data_slot;
VkPrivateDataSlotCreateInfoEXT data_create_info = LvlInitStruct<VkPrivateDataSlotCreateInfoEXT>();
data_create_info.flags = 0;
VkResult err = pfn_vkCreatePrivateDataSlotEXT(m_device->handle(), &data_create_info, NULL, &data_slot);
if (err != VK_SUCCESS) {
printf("Failed to create private data slot, VkResult %d.\n", err);
}
VkSamplerCreateInfo sampler_info = LvlInitStruct<VkSamplerCreateInfo>();
sampler_info.flags = 0;
sampler_info.magFilter = VK_FILTER_LINEAR;
sampler_info.minFilter = VK_FILTER_LINEAR;
sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
sampler_info.mipLodBias = 0.0f;
sampler_info.anisotropyEnable = VK_FALSE;
sampler_info.maxAnisotropy = 16;
sampler_info.compareEnable = VK_FALSE;
sampler_info.compareOp = VK_COMPARE_OP_ALWAYS;
sampler_info.minLod = 0.0f;
sampler_info.maxLod = 0.0f;
sampler_info.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
sampler_info.unnormalizedCoordinates = VK_FALSE;
vk_testing::Sampler sampler(*m_device, sampler_info);
static const uint64_t data_value = 0x70AD;
err = pfn_vkSetPrivateDataEXT(m_device->handle(), VK_OBJECT_TYPE_SAMPLER, (uint64_t)sampler.handle(), data_slot, data_value);
if (err != VK_SUCCESS) {
printf("Failed to set private data. VkResult = %d\n", err);
}
uint64_t data;
pfn_vkGetPrivateDataEXT(m_device->handle(), VK_OBJECT_TYPE_SAMPLER, (uint64_t)sampler.handle(), data_slot, &data);
if (data != data_value) {
m_errorMonitor->SetError("Got unexpected private data, %s.\n");
}
pfn_vkDestroyPrivateDataSlotEXT(m_device->handle(), data_slot, NULL);
}
TEST_F(VkLayerTest, PrivateDataFeature) {
TEST_DESCRIPTION("Test privateData feature not being enabled.");
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredExtensions(VK_EXT_PRIVATE_DATA_EXTENSION_NAME);
ASSERT_NO_FATAL_FAILURE(InitFramework());
if (!AreRequiredExtensionsEnabled()) {
GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported";
}
// feature not enabled
ASSERT_NO_FATAL_FAILURE(InitState());
bool vulkan_13 = (DeviceValidationVersion() >= VK_API_VERSION_1_3);
PFN_vkCreatePrivateDataSlotEXT vkCreatePrivateDataSlotEXT =
(PFN_vkCreatePrivateDataSlotEXT)vk::GetDeviceProcAddr(m_device->handle(), "vkCreatePrivateDataSlotEXT");
VkPrivateDataSlotEXT data_slot;
VkPrivateDataSlotCreateInfoEXT data_create_info = LvlInitStruct<VkPrivateDataSlotCreateInfoEXT>();
data_create_info.flags = 0;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCreatePrivateDataSlot-privateData-04564");
vkCreatePrivateDataSlotEXT(m_device->handle(), &data_create_info, NULL, &data_slot);
m_errorMonitor->VerifyFound();
if (vulkan_13) {
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCreatePrivateDataSlot-privateData-04564");
vk::CreatePrivateDataSlot(m_device->handle(), &data_create_info, NULL, &data_slot);
m_errorMonitor->VerifyFound();
}
}
TEST_F(VkLayerTest, CustomStypeStructString) {
TEST_DESCRIPTION("Positive Test for ability to specify custom pNext structs using a list (string)");
// Create a custom structure
typedef struct CustomStruct {
VkStructureType sType;
const void *pNext;
uint32_t custom_data;
} CustomStruct;
uint32_t custom_stype = 3000300000;
CustomStruct custom_struct;
custom_struct.pNext = nullptr;
custom_struct.sType = static_cast<VkStructureType>(custom_stype);
custom_struct.custom_data = 44;
// Communicate list of structinfo pairs to layers
auto stype_list = CustomStypeList("3000300000,24");
ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor, stype_list.pnext));
ASSERT_NO_FATAL_FAILURE(InitState());
uint32_t queue_family_index = 0;
VkBufferCreateInfo buffer_create_info = LvlInitStruct<VkBufferCreateInfo>();
buffer_create_info.size = 1024;
buffer_create_info.usage = VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
buffer_create_info.queueFamilyIndexCount = 1;
buffer_create_info.pQueueFamilyIndices = &queue_family_index;
VkBufferObj buffer;
buffer.init(*m_device, buffer_create_info);
VkBufferViewCreateInfo bvci = LvlInitStruct<VkBufferViewCreateInfo>(&custom_struct); // Add custom struct through pNext
bvci.buffer = buffer.handle();
bvci.format = VK_FORMAT_R32_SFLOAT;
bvci.range = VK_WHOLE_SIZE;
vk_testing::BufferView buffer_view(*m_device, bvci);
}
TEST_F(VkLayerTest, CustomStypeStructArray) {
TEST_DESCRIPTION("Positive Test for ability to specify custom pNext structs using a vector of integers");
// Create a custom structure
typedef struct CustomStruct {
VkStructureType sType;
const void *pNext;
uint32_t custom_data;
} CustomStruct;
const uint32_t custom_stype_a = 3000300000;
CustomStruct custom_struct_a;
custom_struct_a.pNext = nullptr;
custom_struct_a.sType = static_cast<VkStructureType>(custom_stype_a);
custom_struct_a.custom_data = 44;
const uint32_t custom_stype_b = 3000300001;
CustomStruct custom_struct_b;
custom_struct_b.pNext = &custom_struct_a;
custom_struct_b.sType = static_cast<VkStructureType>(custom_stype_b);
custom_struct_b.custom_data = 88;
// Communicate list of structinfo pairs to layers, including a duplicate which should get filtered out
std::vector<uint32_t> custom_struct_info = {custom_stype_a, sizeof(CustomStruct), custom_stype_b,
sizeof(CustomStruct), custom_stype_a, sizeof(CustomStruct)};
auto stype_list = CustomStypeList(custom_struct_info);
ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor, stype_list.pnext));
ASSERT_NO_FATAL_FAILURE(InitState());
uint32_t queue_family_index = 0;
VkBufferCreateInfo buffer_create_info = LvlInitStruct<VkBufferCreateInfo>();
buffer_create_info.size = 1024;
buffer_create_info.usage = VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
buffer_create_info.queueFamilyIndexCount = 1;
buffer_create_info.pQueueFamilyIndices = &queue_family_index;
VkBufferObj buffer;
buffer.init(*m_device, buffer_create_info);
VkBufferViewCreateInfo bvci = LvlInitStruct<VkBufferViewCreateInfo>(&custom_struct_b); // Add custom struct through pNext
bvci.buffer = buffer.handle();
bvci.format = VK_FORMAT_R32_SFLOAT;
bvci.range = VK_WHOLE_SIZE;
vk_testing::BufferView buffer_view(*m_device, bvci);
}
TEST_F(VkLayerTest, DuplicateMessageLimit) {
TEST_DESCRIPTION("Use the duplicate_message_id setting and verify correct operation");
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
auto msg_limit = DuplicateMsgLimit(3);
ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor, msg_limit.pnext));
ASSERT_NO_FATAL_FAILURE(InitState());
if (!AreRequiredExtensionsEnabled()) {
GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported";
}
PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR =
(PFN_vkGetPhysicalDeviceProperties2KHR)vk::GetInstanceProcAddr(instance(), "vkGetPhysicalDeviceProperties2KHR");
ASSERT_TRUE(vkGetPhysicalDeviceProperties2KHR != nullptr);
// Create an invalid pNext structure to trigger the stateless validation warning
VkBaseOutStructure bogus_struct{};
bogus_struct.sType = static_cast<VkStructureType>(0x33333333);
auto properties2 = LvlInitStruct<VkPhysicalDeviceProperties2KHR>(&bogus_struct);
// Should get the first three errors just fine
m_errorMonitor->SetDesiredFailureMsg((kErrorBit | kWarningBit), "VUID-VkPhysicalDeviceProperties2-pNext-pNext");
vkGetPhysicalDeviceProperties2KHR(gpu(), &properties2);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg((kErrorBit | kWarningBit), "VUID-VkPhysicalDeviceProperties2-pNext-pNext");
vkGetPhysicalDeviceProperties2KHR(gpu(), &properties2);
m_errorMonitor->VerifyFound();
// VUID-VkPhysicalDeviceProperties2-pNext-pNext produces a massive ~3600 character log message, which hits a
// complex string buffer reallocation path inside of the logging code. Make sure it successfully prints out
// the very end of the message.
m_errorMonitor->SetDesiredFailureMsg((kErrorBit | kWarningBit), "is undefined and may not work correctly with validation enabled");
vkGetPhysicalDeviceProperties2KHR(gpu(), &properties2);
m_errorMonitor->VerifyFound();
// Limit should prevent the message from coming through a fourth time
vkGetPhysicalDeviceProperties2KHR(gpu(), &properties2);
}
TEST_F(VkLayerTest, VuidCheckForHashCollisions) {
TEST_DESCRIPTION("Ensure there are no VUID hash collisions");
constexpr uint64_t num_vuids = sizeof(vuid_spec_text) / sizeof(vuid_spec_text[0]);
std::vector<uint32_t> hashes;
hashes.reserve(num_vuids);
for (const auto &vuid_spec_text_pair : vuid_spec_text) {
const uint32_t hash = vvl_vuid_hash(vuid_spec_text_pair.vuid);
hashes.push_back(hash);
}
std::sort(hashes.begin(), hashes.end());
const auto it = std::adjacent_find(hashes.begin(), hashes.end());
ASSERT_TRUE(it == hashes.end());
}
TEST_F(VkLayerTest, VuidHashStability) {
TEST_DESCRIPTION("Ensure stability of VUID hashes clients rely on for filtering");
// Break up VUID strings so they don't get picked up by vk_validation_stats.py
ASSERT_TRUE(vvl_vuid_hash("VUID-"
"VkRenderPassCreateInfo-pNext-01963") == 0xa19880e3);
ASSERT_TRUE(vvl_vuid_hash("VUID-"
"BaryCoordKHR-BaryCoordKHR-04154") == 0xcc72e520);
ASSERT_TRUE(vvl_vuid_hash("VUID-"
"FragDepth-FragDepth-04213") == 0x840af838);
ASSERT_TRUE(vvl_vuid_hash("VUID-"
"RayTmaxKHR-RayTmaxKHR-04349") == 0x8e67514c);
ASSERT_TRUE(vvl_vuid_hash("VUID-"
"RuntimeSpirv-SubgroupUniformControlFlowKHR-06379") == 0x2f574188);
ASSERT_TRUE(vvl_vuid_hash("VUID-"
"StandaloneSpirv-MeshEXT-07111") == 0xee813cd2);
}
TEST_F(VkLayerTest, VuidIdFilterString) {
TEST_DESCRIPTION("Validate that message id string filtering is working");
AddRequiredExtensions(VK_KHR_MAINTENANCE_2_EXTENSION_NAME);
// This test would normally produce an unexpected error or two. Use the message filter instead of
// the error_monitor's SetUnexpectedError to test the filtering.
auto filter_setting = MessageIdFilter("VUID-VkRenderPassCreateInfo-pNext-01963");
ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor, filter_setting.pnext));
if (!AreRequiredExtensionsEnabled()) {
GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported";
}
ASSERT_NO_FATAL_FAILURE(InitState());
VkAttachmentDescription attach = {0,
VK_FORMAT_R8G8B8A8_UNORM,
VK_SAMPLE_COUNT_1_BIT,
VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_DONT_CARE,
VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_DONT_CARE,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL};
VkAttachmentReference ref = {0, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL};
VkSubpassDescription subpass = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 1, &ref, 0, nullptr, nullptr, nullptr, 0, nullptr};
VkInputAttachmentAspectReference iaar = {0, 0, VK_IMAGE_ASPECT_METADATA_BIT};
VkRenderPassInputAttachmentAspectCreateInfo rpiaaci = {VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO,
nullptr, 1, &iaar};
VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, &rpiaaci, 0, 1, &attach, 1, &subpass, 0, nullptr};
m_errorMonitor->SetUnexpectedError("VUID-VkRenderPassCreateInfo2-attachment-02525");
TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, false, "VUID-VkInputAttachmentAspectReference-aspectMask-01964",
nullptr);
}
TEST_F(VkLayerTest, VuidFilterHexInt) {
TEST_DESCRIPTION("Validate that message id hex int filtering is working");
AddRequiredExtensions(VK_KHR_MAINTENANCE_2_EXTENSION_NAME);
// This test would normally produce an unexpected error or two. Use the message filter instead of
// the error_monitor's SetUnexpectedError to test the filtering.
auto filter_setting = MessageIdFilter("0xa19880e3");
ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor, filter_setting.pnext));
if (!AreRequiredExtensionsEnabled()) {
GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported";
}
ASSERT_NO_FATAL_FAILURE(InitState());
VkAttachmentDescription attach = {0,
VK_FORMAT_R8G8B8A8_UNORM,
VK_SAMPLE_COUNT_1_BIT,
VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_DONT_CARE,
VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_DONT_CARE,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL};
VkAttachmentReference ref = {0, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL};
VkSubpassDescription subpass = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 1, &ref, 0, nullptr, nullptr, nullptr, 0, nullptr};
VkInputAttachmentAspectReference iaar = {0, 0, VK_IMAGE_ASPECT_METADATA_BIT};
VkRenderPassInputAttachmentAspectCreateInfo rpiaaci = {VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO,
nullptr, 1, &iaar};
VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, &rpiaaci, 0, 1, &attach, 1, &subpass, 0, nullptr};
m_errorMonitor->SetUnexpectedError("VUID-VkRenderPassCreateInfo2-attachment-02525");
TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, false, "VUID-VkInputAttachmentAspectReference-aspectMask-01964",
nullptr);
}
TEST_F(VkLayerTest, VuidFilterInt) {
TEST_DESCRIPTION("Validate that message id decimal int filtering is working");
AddRequiredExtensions(VK_KHR_MAINTENANCE_2_EXTENSION_NAME);
// This test would normally produce an unexpected error or two. Use the message filter instead of
// the error_monitor's SetUnexpectedError to test the filtering.
auto filter_setting = MessageIdFilter("2711126243");
ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor, filter_setting.pnext));
if (!AreRequiredExtensionsEnabled()) {
GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported";
}
ASSERT_NO_FATAL_FAILURE(InitState());
VkAttachmentDescription attach = {0,
VK_FORMAT_R8G8B8A8_UNORM,
VK_SAMPLE_COUNT_1_BIT,
VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_DONT_CARE,
VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_DONT_CARE,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL};
VkAttachmentReference ref = {0, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL};
VkSubpassDescription subpass = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 1, &ref, 0, nullptr, nullptr, nullptr, 0, nullptr};
VkInputAttachmentAspectReference iaar = {0, 0, VK_IMAGE_ASPECT_METADATA_BIT};
VkRenderPassInputAttachmentAspectCreateInfo rpiaaci = {VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO,
nullptr, 1, &iaar};
VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, &rpiaaci, 0, 1, &attach, 1, &subpass, 0, nullptr};
m_errorMonitor->SetUnexpectedError("VUID-VkRenderPassCreateInfo2-attachment-02525");
TestRenderPassCreate(m_errorMonitor, m_device->device(), &rpci, false, "VUID-VkInputAttachmentAspectReference-aspectMask-01964",
nullptr);
}
struct LayerStatusCheckData {
std::function<void(const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, LayerStatusCheckData *)> callback;
ErrorMonitor *error_monitor;
};
TEST_F(VkLayerTest, LayerInfoMessages) {
TEST_DESCRIPTION("Ensure layer prints startup status messages.");
auto ici = GetInstanceCreateInfo();
LayerStatusCheckData callback_data;
auto local_callback = [](const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, LayerStatusCheckData *data) {
std::string message(pCallbackData->pMessage);
if ((data->error_monitor->GetMessageFlags() & kInformationBit) &&
(message.find("UNASSIGNED-khronos-validation-createinstance-status-message") == std::string::npos)) {
data->error_monitor->SetError("UNASSIGNED-Khronos-validation-createinstance-status-message-not-found");
} else if ((data->error_monitor->GetMessageFlags() & kPerformanceWarningBit) &&
(message.find("UNASSIGNED-khronos-Validation-debug-build-warning-message") == std::string::npos)) {
data->error_monitor->SetError("UNASSIGNED-khronos-validation-createinstance-debug-warning-message-not-found");
}
};
callback_data.error_monitor = m_errorMonitor;
callback_data.callback = local_callback;
VkInstance local_instance;
auto callback_create_info = LvlInitStruct<VkDebugUtilsMessengerCreateInfoEXT>();
callback_create_info.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
callback_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
callback_create_info.pfnUserCallback = DebugUtilsCallback;
callback_create_info.pUserData = &callback_data;
ici.pNext = &callback_create_info;
// Create an instance, error if layer status INFO message not found
ASSERT_VK_SUCCESS(vk::CreateInstance(&ici, nullptr, &local_instance));
vk::DestroyInstance(local_instance, nullptr);
#ifndef NDEBUG
// Create an instance, error if layer DEBUG_BUILD warning message not found
callback_create_info.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
callback_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
ASSERT_VK_SUCCESS(vk::CreateInstance(&ici, nullptr, &local_instance));
vk::DestroyInstance(local_instance, nullptr);
#endif
}
TEST_F(VkLayerTest, RequiredParameter) {
TEST_DESCRIPTION("Specify VK_NULL_HANDLE, NULL, and 0 for required handle, pointer, array, and array count parameters");
ASSERT_NO_FATAL_FAILURE(Init());
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "required parameter pFeatures specified as NULL");
// Specify NULL for a pointer to a handle
// Expected to trigger an error with
// StatelessValidation::ValidateRequiredPointer
vk::GetPhysicalDeviceFeatures(gpu(), NULL);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "required parameter pQueueFamilyPropertyCount specified as NULL");
// Specify NULL for pointer to array count
// Expected to trigger an error with StatelessValidation::ValidateArray
vk::GetPhysicalDeviceQueueFamilyProperties(gpu(), NULL, NULL);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdSetViewport-viewportCount-arraylength");
// Specify 0 for a required array count
// Expected to trigger an error with StatelessValidation::ValidateArray
VkViewport viewport = {0.0f, 0.0f, 64.0f, 64.0f, 0.0f, 1.0f};
m_commandBuffer->SetViewport(0, 0, &viewport);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCreateImage-pCreateInfo-parameter");
// Specify a null pImageCreateInfo struct pointer
VkImage test_image;
vk::CreateImage(device(), NULL, NULL, &test_image);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdSetViewport-pViewports-parameter");
// Specify NULL for a required array
// Expected to trigger an error with StatelessValidation::ValidateArray
m_commandBuffer->SetViewport(0, 1, NULL);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "required parameter memory specified as VK_NULL_HANDLE");
// Specify VK_NULL_HANDLE for a required handle
// Expected to trigger an error with
// StatelessValidation::ValidateRequiredHandle
vk::UnmapMemory(device(), VK_NULL_HANDLE);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "required parameter pFences[0] specified as VK_NULL_HANDLE");
// Specify VK_NULL_HANDLE for a required handle array entry
// Expected to trigger an error with
// StatelessValidation::ValidateRequiredHandleArray
VkFence fence = VK_NULL_HANDLE;
vk::ResetFences(device(), 1, &fence);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "required parameter pAllocateInfo specified as NULL");
// Specify NULL for a required struct pointer
// Expected to trigger an error with
// StatelessValidation::ValidateStructType
VkDeviceMemory memory = VK_NULL_HANDLE;
vk::AllocateMemory(device(), NULL, NULL, &memory);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "value of faceMask must not be 0");
// Specify 0 for a required VkFlags parameter
// Expected to trigger an error with StatelessValidation::ValidateFlags
m_commandBuffer->SetStencilReference(0, 0);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkSubmitInfo-sType-sType");
// Set a bogus sType and see what happens
VkSemaphore semaphore = VK_NULL_HANDLE;
VkPipelineStageFlags stageFlags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
VkSubmitInfo submitInfo = LvlInitStruct<VkSubmitInfo>();
submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = &semaphore;
submitInfo.pWaitDstStageMask = &stageFlags;
submitInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
vk::QueueSubmit(m_device->m_queue, 1, &submitInfo, VK_NULL_HANDLE);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkSubmitInfo-pWaitSemaphores-parameter");
stageFlags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.waitSemaphoreCount = 1;
// Set a null pointer for pWaitSemaphores
submitInfo.pWaitSemaphores = nullptr;
submitInfo.pWaitDstStageMask = &stageFlags;
vk::QueueSubmit(m_device->m_queue, 1, &submitInfo, VK_NULL_HANDLE);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkSubmitInfo-pWaitDstStageMask-parameter");
submitInfo.pWaitSemaphores = &semaphore;
submitInfo.pWaitDstStageMask = nullptr;
vk::QueueSubmit(m_device->m_queue, 1, &submitInfo, VK_NULL_HANDLE);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCreateRenderPass-pCreateInfo-parameter");
VkRenderPass render_pass;
vk::CreateRenderPass(device(), nullptr, nullptr, &render_pass);
m_errorMonitor->VerifyFound();
}
TEST_F(VkLayerTest, SpecLinks) {
TEST_DESCRIPTION("Test that spec links in a typical error message are well-formed");
AddOptionalExtensions(VK_KHR_MAINTENANCE_2_EXTENSION_NAME);
AddOptionalExtensions(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
ASSERT_NO_FATAL_FAILURE(Init());
#ifdef ANNOTATED_SPEC_LINK
bool test_annotated_spec_link = true;
#else // ANNOTATED_SPEC_LINK
bool test_annotated_spec_link = false;
#endif // ANNOTATED_SPEC_LINK
std::string spec_version;
if (test_annotated_spec_link) {
std::string major_version = std::to_string(VK_VERSION_MAJOR(VK_HEADER_VERSION_COMPLETE));
std::string minor_version = std::to_string(VK_VERSION_MINOR(VK_HEADER_VERSION_COMPLETE));
std::string patch_version = std::to_string(VK_VERSION_PATCH(VK_HEADER_VERSION_COMPLETE));
spec_version = "doc/view/" + major_version + "." + minor_version + "." + patch_version + ".0/windows";
} else {
spec_version = "registry/vulkan/specs";
}
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, spec_version);
vk::GetPhysicalDeviceFeatures(gpu(), NULL);
m_errorMonitor->VerifyFound();
// Now generate a 'default' message and check the link
bool ycbcr_support =
(IsExtensionsEnabled(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME) || (DeviceValidationVersion() >= VK_API_VERSION_1_1));
bool maintenance2_support =
(IsExtensionsEnabled(VK_KHR_MAINTENANCE_2_EXTENSION_NAME) || (DeviceValidationVersion() >= VK_API_VERSION_1_1));
if (!((m_device->format_properties(VK_FORMAT_R8_UINT).optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) &&
(ycbcr_support ^ maintenance2_support))) {
GTEST_SKIP() << "Device does not support format and extensions required";
}
VkImageCreateInfo imageInfo = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
nullptr,
0,
VK_IMAGE_TYPE_2D,
VK_FORMAT_R8_UINT,
{128, 128, 1},
1,
1,
VK_SAMPLE_COUNT_1_BIT,
VK_IMAGE_TILING_OPTIMAL,
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
VK_SHARING_MODE_EXCLUSIVE,
0,
nullptr,
VK_IMAGE_LAYOUT_UNDEFINED};
imageInfo.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
VkImageObj mutImage(m_device);
mutImage.init(&imageInfo);
ASSERT_TRUE(mutImage.initialized());
VkImageViewCreateInfo imgViewInfo = LvlInitStruct<VkImageViewCreateInfo>();
imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
imgViewInfo.format = VK_FORMAT_B8G8R8A8_UNORM; // different than createImage
imgViewInfo.subresourceRange.layerCount = 1;
imgViewInfo.subresourceRange.baseMipLevel = 0;
imgViewInfo.subresourceRange.levelCount = 1;
imgViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imgViewInfo.image = mutImage.handle();
// VUIDs 01759 and 01760 should generate 'default' spec URLs, to search the registry
CreateImageViewTest(*this, &imgViewInfo, "Vulkan-Docs/search");
}
TEST_F(VkLayerTest, UsePnextOnlyStructWithoutExtensionEnabled) {
TEST_DESCRIPTION(
"Validate that using VkPipelineTessellationDomainOriginStateCreateInfo in VkPipelineTessellationStateCreateInfo.pNext "
"in a 1.0 context will generate an error message.");
SetTargetApiVersion(VK_API_VERSION_1_0);
ASSERT_NO_FATAL_FAILURE(Init());
ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
if (!m_device->phy().features().tessellationShader) {
GTEST_SKIP() << "Device does not support tessellation shaders";
}
VkShaderObj vs(this, bindStateVertShaderText, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj tcs(this, bindStateTscShaderText, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
VkShaderObj tes(this, bindStateTeshaderText, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT);
VkShaderObj fs(this, bindStateFragShaderText, VK_SHADER_STAGE_FRAGMENT_BIT);
VkPipelineInputAssemblyStateCreateInfo iasci{VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, nullptr, 0,
VK_PRIMITIVE_TOPOLOGY_PATCH_LIST, VK_FALSE};
VkPipelineTessellationDomainOriginStateCreateInfo tessellationDomainOriginStateInfo = {
VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO, VK_NULL_HANDLE,
VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT};
VkPipelineTessellationStateCreateInfo tsci{VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO,
&tessellationDomainOriginStateInfo, 0, 3};
CreatePipelineHelper pipe(*this);
pipe.InitInfo();
pipe.gp_ci_.pTessellationState = &tsci;
pipe.gp_ci_.pInputAssemblyState = &iasci;
pipe.shader_stages_ = {vs.GetStageCreateInfo(), tcs.GetStageCreateInfo(), tes.GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.InitState();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPipelineTessellationStateCreateInfo-pNext-pNext");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(VkLayerTest, PnextOnlyStructValidation) {
TEST_DESCRIPTION("See if checks occur on structs ONLY used in pnext chains.");
AddRequiredExtensions(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
ASSERT_NO_FATAL_FAILURE(InitFramework());
if (!AreRequiredExtensionsEnabled()) {
GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported";
}
// Create a device passing in a bad PdevFeatures2 value
auto indexing_features = LvlInitStruct<VkPhysicalDeviceDescriptorIndexingFeaturesEXT>();
auto features2 = GetPhysicalDeviceFeatures2(indexing_features);
// Set one of the features values to an invalid boolean value
indexing_features.descriptorBindingUniformBufferUpdateAfterBind = 800;
uint32_t queue_node_count;
vk::GetPhysicalDeviceQueueFamilyProperties(gpu(), &queue_node_count, NULL);
std::vector<VkQueueFamilyProperties> queue_props;
queue_props.resize(queue_node_count);
vk::GetPhysicalDeviceQueueFamilyProperties(gpu(), &queue_node_count, queue_props.data());
float priorities[] = {1.0f};
VkDeviceQueueCreateInfo queue_info = LvlInitStruct<VkDeviceQueueCreateInfo>();
queue_info.flags = 0;
queue_info.queueFamilyIndex = 0;
queue_info.queueCount = 1;
queue_info.pQueuePriorities = &priorities[0];
VkDeviceCreateInfo dev_info = LvlInitStruct<VkDeviceCreateInfo>();
dev_info.queueCreateInfoCount = 1;
dev_info.pQueueCreateInfos = &queue_info;
dev_info.enabledLayerCount = 0;
dev_info.ppEnabledLayerNames = NULL;
dev_info.enabledExtensionCount = m_device_extension_names.size();
dev_info.ppEnabledExtensionNames = m_device_extension_names.data();
dev_info.pNext = &features2;
VkDevice dev;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "is neither VK_TRUE nor VK_FALSE");
m_errorMonitor->SetUnexpectedError("Failed to create");
vk::CreateDevice(gpu(), &dev_info, NULL, &dev);
m_errorMonitor->VerifyFound();
}
TEST_F(VkLayerTest, ReservedParameter) {
TEST_DESCRIPTION("Specify a non-zero value for a reserved parameter");
ASSERT_NO_FATAL_FAILURE(Init());
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, " must be 0");
// Specify 0 for a reserved VkFlags parameter
// Expected to trigger an error with
// StatelessValidation::ValidateReservedFlags
VkSemaphore sem_handle = VK_NULL_HANDLE;
VkSemaphoreCreateInfo sem_info = LvlInitStruct<VkSemaphoreCreateInfo>();
sem_info.flags = 1;
vk::CreateSemaphore(device(), &sem_info, NULL, &sem_handle);
m_errorMonitor->VerifyFound();
}
TEST_F(VkLayerTest, DebugMarkerNameTest) {
TEST_DESCRIPTION("Ensure debug marker object names are printed in debug report output");
AddRequiredExtensions(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_DEBUG_MARKER_EXTENSION_NAME);
ASSERT_NO_FATAL_FAILURE(InitFramework());
if (!AreRequiredExtensionsEnabled()) {
GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported";
}
ASSERT_NO_FATAL_FAILURE(InitState());
PFN_vkDebugMarkerSetObjectNameEXT fpvkDebugMarkerSetObjectNameEXT =
(PFN_vkDebugMarkerSetObjectNameEXT)vk::GetInstanceProcAddr(instance(), "vkDebugMarkerSetObjectNameEXT");
if (!(fpvkDebugMarkerSetObjectNameEXT)) {
GTEST_SKIP() << "Can't find fpvkDebugMarkerSetObjectNameEXT; skipped";
}
if (IsPlatform(kMockICD)) {
GTEST_SKIP() << "Skipping object naming test with MockICD.";
}
VkBuffer buffer;
VkDeviceMemory memory_1, memory_2;
std::string memory_name = "memory_name";
VkBufferCreateInfo buffer_create_info = LvlInitStruct<VkBufferCreateInfo>();
buffer_create_info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
buffer_create_info.size = 1;
vk::CreateBuffer(device(), &buffer_create_info, nullptr, &buffer);
VkMemoryRequirements memRequirements;
vk::GetBufferMemoryRequirements(device(), buffer, &memRequirements);
VkMemoryAllocateInfo memory_allocate_info = LvlInitStruct<VkMemoryAllocateInfo>();
memory_allocate_info.allocationSize = memRequirements.size;
memory_allocate_info.memoryTypeIndex = 0;
vk::AllocateMemory(device(), &memory_allocate_info, nullptr, &memory_1);
vk::AllocateMemory(device(), &memory_allocate_info, nullptr, &memory_2);
VkDebugMarkerObjectNameInfoEXT name_info = LvlInitStruct<VkDebugMarkerObjectNameInfoEXT>();
name_info.object = (uint64_t)memory_2;
name_info.objectType = VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT;
name_info.pObjectName = memory_name.c_str();
fpvkDebugMarkerSetObjectNameEXT(device(), &name_info);
vk::BindBufferMemory(device(), buffer, memory_1, 0);
// Test core_validation layer
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, memory_name);
vk::BindBufferMemory(device(), buffer, memory_2, 0);
m_errorMonitor->VerifyFound();
vk::FreeMemory(device(), memory_1, nullptr);
memory_1 = VK_NULL_HANDLE;
vk::FreeMemory(device(), memory_2, nullptr);
memory_2 = VK_NULL_HANDLE;
vk::DestroyBuffer(device(), buffer, nullptr);
buffer = VK_NULL_HANDLE;
VkCommandBuffer commandBuffer;
std::string commandBuffer_name = "command_buffer_name";
VkCommandPoolCreateInfo pool_create_info = LvlInitStruct<VkCommandPoolCreateInfo>();
pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_;
pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
vk_testing::CommandPool command_pool_1(*m_device, pool_create_info);
vk_testing::CommandPool command_pool_2(*m_device, pool_create_info);
VkCommandBufferAllocateInfo command_buffer_allocate_info = LvlInitStruct<VkCommandBufferAllocateInfo>();
command_buffer_allocate_info.commandPool = command_pool_1.handle();
command_buffer_allocate_info.commandBufferCount = 1;
command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
vk::AllocateCommandBuffers(device(), &command_buffer_allocate_info, &commandBuffer);
name_info.object = (uint64_t)commandBuffer;
name_info.objectType = VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT;
name_info.pObjectName = commandBuffer_name.c_str();
fpvkDebugMarkerSetObjectNameEXT(device(), &name_info);
VkCommandBufferBeginInfo cb_begin_Info = LvlInitStruct<VkCommandBufferBeginInfo>();
cb_begin_Info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vk::BeginCommandBuffer(commandBuffer, &cb_begin_Info);
const VkRect2D scissor = {{-1, 0}, {16, 16}};
const VkRect2D scissors[] = {scissor, scissor};
// Test parameter_validation layer
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, commandBuffer_name);
vk::CmdSetScissor(commandBuffer, 0, 1, scissors);
m_errorMonitor->VerifyFound();
// Test object_tracker layer
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, commandBuffer_name);
vk::FreeCommandBuffers(device(), command_pool_2.handle(), 1, &commandBuffer);
m_errorMonitor->VerifyFound();
}
TEST_F(VkLayerTest, DebugUtilsNameTest) {
TEST_DESCRIPTION("Ensure debug utils object names are printed in debug messenger output");
AddRequiredExtensions(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
if (!AreRequiredExtensionsEnabled()) {
GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported";
}
ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor));
ASSERT_NO_FATAL_FAILURE(InitState());
if (IsPlatform(kMockICD)) {
GTEST_SKIP() << "Skipping object naming test with MockICD.";
}
DebugUtilsLabelCheckData callback_data;
auto empty_callback = [](const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, DebugUtilsLabelCheckData *data) {
data->count++;
};
callback_data.count = 0;
callback_data.callback = empty_callback;
auto callback_create_info = LvlInitStruct<VkDebugUtilsMessengerCreateInfoEXT>();
callback_create_info.messageSeverity =
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
callback_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
callback_create_info.pfnUserCallback = DebugUtilsCallback;
callback_create_info.pUserData = &callback_data;
VkDebugUtilsMessengerEXT my_messenger = VK_NULL_HANDLE;
vk::CreateDebugUtilsMessengerEXT(instance(), &callback_create_info, nullptr, &my_messenger);
VkBuffer buffer;
VkDeviceMemory memory_1, memory_2;
std::string memory_name = "memory_name";
VkBufferCreateInfo buffer_create_info = LvlInitStruct<VkBufferCreateInfo>();
buffer_create_info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
buffer_create_info.size = 1;
vk::CreateBuffer(device(), &buffer_create_info, nullptr, &buffer);
VkMemoryRequirements memRequirements;
vk::GetBufferMemoryRequirements(device(), buffer, &memRequirements);
VkMemoryAllocateInfo memory_allocate_info = LvlInitStruct<VkMemoryAllocateInfo>();
memory_allocate_info.allocationSize = memRequirements.size;
memory_allocate_info.memoryTypeIndex = 0;
vk::AllocateMemory(device(), &memory_allocate_info, nullptr, &memory_1);
vk::AllocateMemory(device(), &memory_allocate_info, nullptr, &memory_2);
VkDebugUtilsObjectNameInfoEXT name_info = LvlInitStruct<VkDebugUtilsObjectNameInfoEXT>();
name_info.objectType = VK_OBJECT_TYPE_DEVICE_MEMORY;
name_info.pObjectName = memory_name.c_str();
// Pass in bad handle make sure ObjectTracker catches it
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkDebugUtilsObjectNameInfoEXT-objectType-02590");
name_info.objectHandle = (uint64_t)0xcadecade;
vk::SetDebugUtilsObjectNameEXT(device(), &name_info);
m_errorMonitor->VerifyFound();
// Pass in null handle
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkSetDebugUtilsObjectNameEXT-pNameInfo-02588");
name_info.objectHandle = 0;
vk::SetDebugUtilsObjectNameEXT(device(), &name_info);
m_errorMonitor->VerifyFound();
// Pass in 'unknown' object type and see if parameter validation catches it
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkSetDebugUtilsObjectNameEXT-pNameInfo-02587");
name_info.objectHandle = (uint64_t)memory_2;
name_info.objectType = VK_OBJECT_TYPE_UNKNOWN;
vk::SetDebugUtilsObjectNameEXT(device(), &name_info);
m_errorMonitor->VerifyFound();
name_info.objectType = VK_OBJECT_TYPE_DEVICE_MEMORY;
vk::SetDebugUtilsObjectNameEXT(device(), &name_info);
vk::BindBufferMemory(device(), buffer, memory_1, 0);
// Test core_validation layer
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, memory_name);
vk::BindBufferMemory(device(), buffer, memory_2, 0);
m_errorMonitor->VerifyFound();
vk::FreeMemory(device(), memory_1, nullptr);
memory_1 = VK_NULL_HANDLE;
vk::FreeMemory(device(), memory_2, nullptr);
memory_2 = VK_NULL_HANDLE;
vk::DestroyBuffer(device(), buffer, nullptr);
buffer = VK_NULL_HANDLE;
VkCommandBuffer commandBuffer;
std::string commandBuffer_name = "command_buffer_name";
VkCommandPoolCreateInfo pool_create_info = LvlInitStruct<VkCommandPoolCreateInfo>();
pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_;
pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
vk_testing::CommandPool command_pool_1(*m_device, pool_create_info);
vk_testing::CommandPool command_pool_2(*m_device, pool_create_info);
VkCommandBufferAllocateInfo command_buffer_allocate_info = LvlInitStruct<VkCommandBufferAllocateInfo>();
command_buffer_allocate_info.commandPool = command_pool_1.handle();
command_buffer_allocate_info.commandBufferCount = 1;
command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
vk::AllocateCommandBuffers(device(), &command_buffer_allocate_info, &commandBuffer);
name_info.objectHandle = (uint64_t)commandBuffer;
name_info.objectType = VK_OBJECT_TYPE_COMMAND_BUFFER;
name_info.pObjectName = commandBuffer_name.c_str();
vk::SetDebugUtilsObjectNameEXT(device(), &name_info);
VkCommandBufferBeginInfo cb_begin_Info = LvlInitStruct<VkCommandBufferBeginInfo>();
cb_begin_Info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vk::BeginCommandBuffer(commandBuffer, &cb_begin_Info);
const VkRect2D scissor = {{-1, 0}, {16, 16}};
const VkRect2D scissors[] = {scissor, scissor};
auto command_label = LvlInitStruct<VkDebugUtilsLabelEXT>();
command_label.pLabelName = "Command Label 0123";
command_label.color[0] = 0.;
command_label.color[1] = 1.;
command_label.color[2] = 2.;
command_label.color[3] = 3.0;
bool command_label_test = false;
auto command_label_callback = [command_label, &command_label_test](const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData,
DebugUtilsLabelCheckData *data) {
data->count++;
command_label_test = false;
if (pCallbackData->cmdBufLabelCount == 1) {
command_label_test = pCallbackData->pCmdBufLabels[0] == command_label;
}
};
callback_data.callback = command_label_callback;
vk::CmdInsertDebugUtilsLabelEXT(commandBuffer, &command_label);
// Test parameter_validation layer
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, commandBuffer_name);
vk::CmdSetScissor(commandBuffer, 0, 1, scissors);
m_errorMonitor->VerifyFound();
// Check the label test
if (!command_label_test) {
ADD_FAILURE() << "Command label '" << command_label.pLabelName << "' not passed to callback.";
}
// Test object_tracker layer
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, commandBuffer_name);
vk::FreeCommandBuffers(device(), command_pool_2.handle(), 1, &commandBuffer);
m_errorMonitor->VerifyFound();
vk::DestroyDebugUtilsMessengerEXT(instance(), my_messenger, nullptr);
}
TEST_F(VkLayerTest, InvalidStructSType) {
TEST_DESCRIPTION("Specify an invalid VkStructureType for a Vulkan structure's sType field");
ASSERT_NO_FATAL_FAILURE(Init());
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "parameter pAllocateInfo->sType must be");
// Zero struct memory, effectively setting sType to
// VK_STRUCTURE_TYPE_APPLICATION_INFO
// Expected to trigger an error with
// StatelessValidation::ValidateStructType
VkMemoryAllocateInfo alloc_info = {};
VkDeviceMemory memory = VK_NULL_HANDLE;
vk::AllocateMemory(device(), &alloc_info, NULL, &memory);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "parameter pSubmits[0].sType must be");
// Zero struct memory, effectively setting sType to
// VK_STRUCTURE_TYPE_APPLICATION_INFO
// Expected to trigger an error with
// StatelessValidation::ValidateStructTypeArray
VkSubmitInfo submit_info = {};
vk::QueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE);
m_errorMonitor->VerifyFound();
}
TEST_F(VkLayerTest, InvalidStructPNext) {
TEST_DESCRIPTION("Specify an invalid value for a Vulkan structure's pNext field");
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
ASSERT_NO_FATAL_FAILURE(Init());
if (!AreRequiredExtensionsEnabled()) {
GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported";
}
PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR =
(PFN_vkGetPhysicalDeviceProperties2KHR)vk::GetInstanceProcAddr(instance(), "vkGetPhysicalDeviceProperties2KHR");
ASSERT_TRUE(vkGetPhysicalDeviceProperties2KHR != nullptr);
m_errorMonitor->SetDesiredFailureMsg((kErrorBit | kWarningBit), "VUID-VkCommandPoolCreateInfo-pNext-pNext");
// Set VkCommandPoolCreateInfo::pNext to a non-NULL value, when pNext must be NULL.
// Need to pick a function that has no allowed pNext structure types.
// Expected to trigger an error with StatelessValidation::ValidateStructPnext
VkCommandPool pool = VK_NULL_HANDLE;
auto pool_ci = LvlInitStruct<VkCommandPoolCreateInfo>();
auto app_info = LvlInitStruct<VkApplicationInfo>();
pool_ci.pNext = &app_info;
vk::CreateCommandPool(device(), &pool_ci, NULL, &pool);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg((kErrorBit | kWarningBit), " chain includes a structure with unexpected VkStructureType ");
// Set VkMemoryAllocateInfo::pNext to a non-NULL value, but use
// a function that has allowed pNext structure types and specify
// a structure type that is not allowed.
// Expected to trigger an error with StatelessValidation::ValidateStructPnext
VkDeviceMemory memory = VK_NULL_HANDLE;
VkMemoryAllocateInfo memory_alloc_info = LvlInitStruct<VkMemoryAllocateInfo>(&app_info);
vk::AllocateMemory(device(), &memory_alloc_info, NULL, &memory);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg((kErrorBit | kWarningBit), " chain includes a structure with unexpected VkStructureType ");
// Same concept as above, but unlike vkAllocateMemory where VkMemoryAllocateInfo is a const
// in vkGetPhysicalDeviceProperties2, VkPhysicalDeviceProperties2 is not a const
VkPhysicalDeviceProperties2 physical_device_properties2 = LvlInitStruct<VkPhysicalDeviceProperties2>(&app_info);
vkGetPhysicalDeviceProperties2KHR(gpu(), &physical_device_properties2);
m_errorMonitor->VerifyFound();
}
TEST_F(VkLayerTest, UnrecognizedValueOutOfRange) {
ASSERT_NO_FATAL_FAILURE(Init());
m_errorMonitor->SetDesiredFailureMsg(kErrorBit,
"does not fall within the begin..end range of the core VkFormat enumeration tokens");
// Specify an invalid VkFormat value
// Expected to trigger an error with
// StatelessValidation::ValidateRangedEnum
VkFormatProperties format_properties;
vk::GetPhysicalDeviceFormatProperties(gpu(), static_cast<VkFormat>(8000), &format_properties);
m_errorMonitor->VerifyFound();
}
TEST_F(VkLayerTest, UnrecognizedValueBadMask) {
ASSERT_NO_FATAL_FAILURE(Init());
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "contains flag bits that are not recognized members of");
// Specify an invalid VkFlags bitmask value
// Expected to trigger an error with StatelessValidation::ValidateFlags
VkImageFormatProperties image_format_properties;
vk::GetPhysicalDeviceImageFormatProperties(gpu(), VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL,
static_cast<VkImageUsageFlags>(1 << 25), 0, &image_format_properties);
m_errorMonitor->VerifyFound();
}
TEST_F(VkLayerTest, UnrecognizedValueBadFlag) {
ASSERT_NO_FATAL_FAILURE(Init());
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "contains flag bits that are not recognized members of");
// Specify an invalid VkFlags array entry
// Expected to trigger an error with StatelessValidation::ValidateFlagsArray
VkSemaphore semaphore;
VkSemaphoreCreateInfo semaphore_create_info = LvlInitStruct<VkSemaphoreCreateInfo>();
vk::CreateSemaphore(m_device->device(), &semaphore_create_info, nullptr, &semaphore);
// `stage_flags` is set to a value which, currently, is not a defined stage flag
// `VK_IMAGE_ASPECT_FLAG_BITS_MAX_ENUM` works well for this
VkPipelineStageFlags stage_flags = VK_IMAGE_ASPECT_FLAG_BITS_MAX_ENUM;
// `waitSemaphoreCount` *must* be greater than 0 to perform this check
VkSubmitInfo submit_info = LvlInitStruct<VkSubmitInfo>();
submit_info.waitSemaphoreCount = 1;
submit_info.pWaitSemaphores = &semaphore;
submit_info.pWaitDstStageMask = &stage_flags;
vk::QueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE);
vk::DestroySemaphore(m_device->device(), semaphore, nullptr);
m_errorMonitor->VerifyFound();
}
TEST_F(VkLayerTest, UnrecognizedValueBadBool) {
// Make sure using VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE doesn't trigger a false positive.
AddRequiredExtensions(VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME);
ASSERT_NO_FATAL_FAILURE(InitFramework());
if (!AreRequiredExtensionsEnabled()) {
GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported";
}
ASSERT_NO_FATAL_FAILURE(InitState());
// Specify an invalid VkBool32 value, expecting a warning with StatelessValidation::ValidateBool32
VkSamplerCreateInfo sampler_info = SafeSaneSamplerCreateInfo();
sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE;
sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE;
sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE;
// Not VK_TRUE or VK_FALSE
sampler_info.anisotropyEnable = 3;
CreateSamplerTest(*this, &sampler_info, "is neither VK_TRUE nor VK_FALSE");
}
TEST_F(VkLayerTest, UnrecognizedValueMaxEnum) {
ASSERT_NO_FATAL_FAILURE(Init());
// Specify MAX_ENUM
VkFormatProperties format_properties;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "does not fall within the begin..end range");
vk::GetPhysicalDeviceFormatProperties(gpu(), VK_FORMAT_MAX_ENUM, &format_properties);
m_errorMonitor->VerifyFound();
}
TEST_F(VkLayerTest, LeakAnObject) {
TEST_DESCRIPTION("Create a fence and destroy its device without first destroying the fence.");
ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor));
if (!IsPlatform(kMockICD)) {
// This test leaks a fence (on purpose) and should not be run on a real driver
GTEST_SKIP() << "This test only runs on the mock ICD";
}
// Workaround for overzealous layers checking even the guaranteed 0th queue family
const auto q_props = vk_testing::PhysicalDevice(gpu()).queue_properties();
ASSERT_TRUE(q_props.size() > 0);
ASSERT_TRUE(q_props[0].queueCount > 0);
const float q_priority[] = {1.0f};
VkDeviceQueueCreateInfo queue_ci = LvlInitStruct<VkDeviceQueueCreateInfo>();
queue_ci.queueFamilyIndex = 0;
queue_ci.queueCount = 1;
queue_ci.pQueuePriorities = q_priority;
VkDeviceCreateInfo device_ci = LvlInitStruct<VkDeviceCreateInfo>();
device_ci.queueCreateInfoCount = 1;
device_ci.pQueueCreateInfos = &queue_ci;
VkDevice leaky_device;
ASSERT_VK_SUCCESS(vk::CreateDevice(gpu(), &device_ci, nullptr, &leaky_device));
const VkFenceCreateInfo fence_ci = LvlInitStruct<VkFenceCreateInfo>();
VkFence leaked_fence;
ASSERT_VK_SUCCESS(vk::CreateFence(leaky_device, &fence_ci, nullptr, &leaked_fence));
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkDestroyDevice-device-00378");
vk::DestroyDevice(leaky_device, nullptr);
m_errorMonitor->VerifyFound();
// There's no way we can destroy the fence at this point. Even though DestroyDevice failed, the loader has already removed
// references to the device
m_errorMonitor->SetUnexpectedError("VUID-vkDestroyDevice-device-00378");
m_errorMonitor->SetUnexpectedError("UNASSIGNED-ObjectTracker-ObjectLeak");
}
TEST_F(VkLayerTest, UseObjectWithWrongDevice) {
TEST_DESCRIPTION(
"Try to destroy a render pass object using a device other than the one it was created on. This should generate a distinct "
"error from the invalid handle error.");
// Create first device and renderpass
ASSERT_NO_FATAL_FAILURE(Init());
ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
// Create second device
float priorities[] = {1.0f};
VkDeviceQueueCreateInfo queue_info = LvlInitStruct<VkDeviceQueueCreateInfo>();
queue_info.flags = 0;
queue_info.queueFamilyIndex = 0;
queue_info.queueCount = 1;
queue_info.pQueuePriorities = &priorities[0];
VkDeviceCreateInfo device_create_info = LvlInitStruct<VkDeviceCreateInfo>();
auto features = m_device->phy().features();
device_create_info.queueCreateInfoCount = 1;
device_create_info.pQueueCreateInfos = &queue_info;
device_create_info.enabledLayerCount = 0;
device_create_info.ppEnabledLayerNames = NULL;
device_create_info.pEnabledFeatures = &features;
VkDevice second_device;
ASSERT_VK_SUCCESS(vk::CreateDevice(gpu(), &device_create_info, NULL, &second_device));
// Try to destroy the renderpass from the first device using the second device
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkDestroyRenderPass-renderPass-parent");
vk::DestroyRenderPass(second_device, m_renderPass, NULL);
m_errorMonitor->VerifyFound();
vk::DestroyDevice(second_device, NULL);
}
TEST_F(VkLayerTest, InvalidAllocationCallbacks) {
TEST_DESCRIPTION("Test with invalid VkAllocationCallbacks");
ASSERT_NO_FATAL_FAILURE(Init());
const std::optional queueFamilyIndex = DeviceObj()->QueueFamilyMatching(0, 0, true);
if (!queueFamilyIndex) {
GTEST_SKIP() << "Required queue families not present";
}
// vk::CreateInstance, and vk::CreateDevice tend to crash in the Loader Trampoline ATM, so choosing vk::CreateCommandPool
const VkCommandPoolCreateInfo cpci = {VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, nullptr, 0, queueFamilyIndex.value()};
VkCommandPool cmdPool;
struct Alloc {
static VKAPI_ATTR void *VKAPI_CALL alloc(void *, size_t, size_t, VkSystemAllocationScope) { return nullptr; };
static VKAPI_ATTR void *VKAPI_CALL realloc(void *, void *, size_t, size_t, VkSystemAllocationScope) { return nullptr; };
static VKAPI_ATTR void VKAPI_CALL free(void *, void *){};
static VKAPI_ATTR void VKAPI_CALL internalAlloc(void *, size_t, VkInternalAllocationType, VkSystemAllocationScope){};
static VKAPI_ATTR void VKAPI_CALL internalFree(void *, size_t, VkInternalAllocationType, VkSystemAllocationScope){};
};
{
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkAllocationCallbacks-pfnAllocation-00632");
const VkAllocationCallbacks allocator = {nullptr, nullptr, Alloc::realloc, Alloc::free, nullptr, nullptr};
vk::CreateCommandPool(device(), &cpci, &allocator, &cmdPool);
m_errorMonitor->VerifyFound();
}
{
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkAllocationCallbacks-pfnReallocation-00633");
const VkAllocationCallbacks allocator = {nullptr, Alloc::alloc, nullptr, Alloc::free, nullptr, nullptr};
vk::CreateCommandPool(device(), &cpci, &allocator, &cmdPool);
m_errorMonitor->VerifyFound();
}
{
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkAllocationCallbacks-pfnFree-00634");
const VkAllocationCallbacks allocator = {nullptr, Alloc::alloc, Alloc::realloc, nullptr, nullptr, nullptr};
vk::CreateCommandPool(device(), &cpci, &allocator, &cmdPool);
m_errorMonitor->VerifyFound();
}
{
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkAllocationCallbacks-pfnInternalAllocation-00635");
const VkAllocationCallbacks allocator = {nullptr, Alloc::alloc, Alloc::realloc, Alloc::free, nullptr, Alloc::internalFree};
vk::CreateCommandPool(device(), &cpci, &allocator, &cmdPool);
m_errorMonitor->VerifyFound();
}
{
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkAllocationCallbacks-pfnInternalAllocation-00635");
const VkAllocationCallbacks allocator = {nullptr, Alloc::alloc, Alloc::realloc, Alloc::free, Alloc::internalAlloc, nullptr};
vk::CreateCommandPool(device(), &cpci, &allocator, &cmdPool);
m_errorMonitor->VerifyFound();
}
}
TEST_F(VkLayerTest, MismatchedQueueFamiliesOnSubmit) {
TEST_DESCRIPTION(
"Submit command buffer created using one queue family and attempt to submit them on a queue created in a different queue "
"family.");
ASSERT_NO_FATAL_FAILURE(Init()); // assumes it initializes all queue families on vk::CreateDevice
// This test is meaningless unless we have multiple queue families
auto queue_family_properties = m_device->phy().queue_properties();
std::vector<uint32_t> queue_families;
for (uint32_t i = 0; i < queue_family_properties.size(); ++i)
if (queue_family_properties[i].queueCount > 0) queue_families.push_back(i);
if (queue_families.size() < 2) {
GTEST_SKIP() << "Device only has one queue family";
}
const uint32_t queue_family = queue_families[0];
const uint32_t other_queue_family = queue_families[1];
VkQueue other_queue;
vk::GetDeviceQueue(m_device->device(), other_queue_family, 0, &other_queue);
VkCommandPoolObj cmd_pool(m_device, queue_family);
VkCommandBufferObj cmd_buff(m_device, &cmd_pool);
cmd_buff.begin();
cmd_buff.end();
// Submit on the wrong queue
VkSubmitInfo submit_info = LvlInitStruct<VkSubmitInfo>();
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &cmd_buff.handle();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkQueueSubmit-pCommandBuffers-00074");
vk::QueueSubmit(other_queue, 1, &submit_info, VK_NULL_HANDLE);
m_errorMonitor->VerifyFound();
}
TEST_F(VkLayerTest, DeviceFeature2AndVertexAttributeDivisorExtensionUnenabled) {
TEST_DESCRIPTION(
"Test unenabled VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME & "
"VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME.");
VkPhysicalDeviceFeatures2 pd_features2 = LvlInitStruct<VkPhysicalDeviceFeatures2>();
ASSERT_NO_FATAL_FAILURE(Init());
vk_testing::QueueCreateInfoArray queue_info(m_device->queue_props);
VkDeviceCreateInfo device_create_info = LvlInitStruct<VkDeviceCreateInfo>(&pd_features2);
device_create_info.queueCreateInfoCount = queue_info.size();
device_create_info.pQueueCreateInfos = queue_info.data();
VkDevice testDevice;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkDeviceCreateInfo-pNext-pNext");
m_errorMonitor->SetUnexpectedError("Failed to create device chain");
vk::CreateDevice(gpu(), &device_create_info, NULL, &testDevice);
m_errorMonitor->VerifyFound();
VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT vadf = LvlInitStruct<VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT>();
device_create_info.pNext = &vadf;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VK_EXT_vertex_attribute_divisor must be enabled when it creates a device");
m_errorMonitor->SetUnexpectedError("Failed to create device chain");
vk::CreateDevice(gpu(), &device_create_info, NULL, &testDevice);
m_errorMonitor->VerifyFound();
}
TEST_F(VkLayerTest, Features12Features13AndpNext) {
TEST_DESCRIPTION("Test VkPhysicalDeviceVulkan12Features and illegal struct in pNext");
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_8BIT_STORAGE_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_16BIT_STORAGE_EXTENSION_NAME);
ASSERT_NO_FATAL_FAILURE(Init());
if (!AreRequiredExtensionsEnabled()) {
GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported";
}
if (DeviceValidationVersion() < VK_API_VERSION_1_2) {
GTEST_SKIP() << "At least Vulkan version 1.2 is required";
}
VkPhysicalDevice16BitStorageFeatures sixteen_bit = LvlInitStruct<VkPhysicalDevice16BitStorageFeatures>();
sixteen_bit.storageBuffer16BitAccess = true;
VkPhysicalDeviceVulkan11Features features11 = LvlInitStruct<VkPhysicalDeviceVulkan11Features>(&sixteen_bit);
features11.storageBuffer16BitAccess = true;
VkPhysicalDevice8BitStorageFeatures eight_bit = LvlInitStruct<VkPhysicalDevice8BitStorageFeatures>(&features11);
eight_bit.storageBuffer8BitAccess = true;
VkPhysicalDeviceVulkan12Features features12 = LvlInitStruct<VkPhysicalDeviceVulkan12Features>(&eight_bit);
features12.storageBuffer8BitAccess = true;
VkPhysicalDeviceVulkan13Features features13 = {};
VkPhysicalDeviceDynamicRenderingFeatures dyn_rendering_features = {};
if (DeviceValidationVersion() >= VK_API_VERSION_1_3) {
dyn_rendering_features = LvlInitStruct<VkPhysicalDeviceDynamicRenderingFeatures>();
dyn_rendering_features.dynamicRendering = true;
dyn_rendering_features.pNext = &eight_bit;
features13 = LvlInitStruct<VkPhysicalDeviceVulkan13Features>(&dyn_rendering_features);
features13.dynamicRendering = true;
features12.pNext = &features13;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkDeviceCreateInfo-pNext-06532");
}
vk_testing::PhysicalDevice physical_device(gpu());
vk_testing::QueueCreateInfoArray queue_info(physical_device.queue_properties());
std::vector<VkDeviceQueueCreateInfo> create_queue_infos;
auto qci = queue_info.data();
for (uint32_t i = 0; i < queue_info.size(); ++i) {
if (qci[i].queueCount) {
create_queue_infos.push_back(qci[i]);
}
}
VkDeviceCreateInfo device_create_info = LvlInitStruct<VkDeviceCreateInfo>(&features12);
device_create_info.queueCreateInfoCount = queue_info.size();
device_create_info.pQueueCreateInfos = queue_info.data();
VkDevice testDevice;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkDeviceCreateInfo-pNext-02829");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkDeviceCreateInfo-pNext-02830");
m_errorMonitor->SetUnexpectedError("Failed to create device chain");
vk::CreateDevice(gpu(), &device_create_info, NULL, &testDevice);
m_errorMonitor->VerifyFound();
}
TEST_F(VkLayerTest, RequiredPromotedFeaturesExtensions) {
TEST_DESCRIPTION("Checks that features are enabled if extension is passed in for promoted extensions with requirement.");
// targets each possible version
SetTargetApiVersion(VK_API_VERSION_1_1);
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor));
if (DeviceValidationVersion() < VK_API_VERSION_1_1) {
GTEST_SKIP() << "At least Vulkan version 1.1 is required";
}
const bool test_1_2 = (DeviceValidationVersion() >= VK_API_VERSION_1_2);
if (!AreRequiredExtensionsEnabled()) {
GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported";
}
vk_testing::PhysicalDevice physical_device(gpu());
vk_testing::QueueCreateInfoArray queue_info(physical_device.queue_properties());
std::vector<VkDeviceQueueCreateInfo> create_queue_infos;
auto qci = queue_info.data();
for (uint32_t i = 0; i < queue_info.size(); ++i) {
if (qci[i].queueCount) {
create_queue_infos.push_back(qci[i]);
}
}
// Explicity set all tested features to false
VkPhysicalDeviceVulkan12Features features12 = LvlInitStruct<VkPhysicalDeviceVulkan12Features>();
features12.drawIndirectCount = VK_FALSE;
features12.samplerMirrorClampToEdge = VK_FALSE;
features12.descriptorIndexing = VK_FALSE;
features12.samplerFilterMinmax = VK_FALSE;
features12.shaderOutputViewportIndex = VK_FALSE;
features12.shaderOutputLayer = VK_TRUE; // Set true since both shader_viewport features need to true
VkPhysicalDeviceVulkan11Features features11 = LvlInitStruct<VkPhysicalDeviceVulkan11Features>();
features11.pNext = (test_1_2 == true) ? &features12 : nullptr;
features11.shaderDrawParameters = VK_FALSE;
std::vector<const char *> device_extensions;
// Go through each extension and if supported add to list and add failure to check for
if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME)) {
device_extensions.push_back(VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-04476");
}
if (test_1_2 == true) {
if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME)) {
device_extensions.push_back(VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-02831");
}
if (DeviceExtensionSupported(gpu(), nullptr, VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME)) {
device_extensions.push_back(VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-02832");
}
if (DeviceExtensionSupported(gpu(), nullptr, VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME)) {
device_extensions.push_back(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
device_extensions.push_back(VK_KHR_MAINTENANCE_3_EXTENSION_NAME);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-02833");
}
if (DeviceExtensionSupported(gpu(), nullptr, VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME)) {
device_extensions.push_back(VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-02834");
}
if (DeviceExtensionSupported(gpu(), nullptr, VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME)) {
device_extensions.push_back(VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-02835");
}
} else {
// VkPhysicalDeviceVulkan11Features was not added until Vulkan 1.2
m_errorMonitor->SetUnexpectedError("VUID-VkDeviceCreateInfo-pNext-pNext");
}
VkDeviceCreateInfo device_create_info = LvlInitStruct<VkDeviceCreateInfo>(&features11);
device_create_info.queueCreateInfoCount = queue_info.size();
device_create_info.pQueueCreateInfos = queue_info.data();
device_create_info.ppEnabledExtensionNames = device_extensions.data();
device_create_info.enabledExtensionCount = device_extensions.size();
VkDevice testDevice;
m_errorMonitor->SetUnexpectedError("Failed to create device chain");
vk::CreateDevice(gpu(), &device_create_info, NULL, &testDevice);
m_errorMonitor->VerifyFound();
}
TEST_F(VkLayerTest, FeaturesVariablePointer) {
TEST_DESCRIPTION("Checks VK_KHR_variable_pointers features.");
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_VARIABLE_POINTERS_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME);
ASSERT_NO_FATAL_FAILURE(InitFramework());
if (!AreRequiredExtensionsEnabled()) {
GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported";
}
std::vector<const char *> device_extensions;
device_extensions.push_back(VK_KHR_VARIABLE_POINTERS_EXTENSION_NAME);
device_extensions.push_back(VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME);
// Create a device that enables variablePointers but not variablePointersStorageBuffer
auto variable_features = LvlInitStruct<VkPhysicalDeviceVariablePointersFeatures>();
auto features2 = GetPhysicalDeviceFeatures2(variable_features);
if (variable_features.variablePointers == VK_FALSE) {
GTEST_SKIP() << "variablePointer feature not supported";
}
variable_features.variablePointersStorageBuffer = VK_FALSE;
vk_testing::PhysicalDevice physical_device(gpu());
vk_testing::QueueCreateInfoArray queue_info(physical_device.queue_properties());
std::vector<VkDeviceQueueCreateInfo> create_queue_infos;
auto qci = queue_info.data();
for (uint32_t i = 0; i < queue_info.size(); ++i) {
if (qci[i].queueCount) {
create_queue_infos.push_back(qci[i]);
}
}
VkDeviceCreateInfo device_create_info = LvlInitStruct<VkDeviceCreateInfo>(&features2);
device_create_info.queueCreateInfoCount = queue_info.size();
device_create_info.pQueueCreateInfos = queue_info.data();
device_create_info.ppEnabledExtensionNames = device_extensions.data();
device_create_info.enabledExtensionCount = device_extensions.size();
VkDevice testDevice;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPhysicalDeviceVariablePointersFeatures-variablePointers-01431");
vk::CreateDevice(gpu(), &device_create_info, NULL, &testDevice);
m_errorMonitor->VerifyFound();
}
TEST_F(VkLayerTest, ValidationCacheTestBadMerge) {
AddRequiredExtensions(VK_EXT_VALIDATION_CACHE_EXTENSION_NAME);
ASSERT_NO_FATAL_FAILURE(InitFramework());
if (!AreRequiredExtensionsEnabled()) {
GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported";
}
ASSERT_NO_FATAL_FAILURE(InitState());
// Load extension functions
auto fpCreateValidationCache =
(PFN_vkCreateValidationCacheEXT)vk::GetDeviceProcAddr(m_device->device(), "vkCreateValidationCacheEXT");
auto fpDestroyValidationCache =
(PFN_vkDestroyValidationCacheEXT)vk::GetDeviceProcAddr(m_device->device(), "vkDestroyValidationCacheEXT");
auto fpMergeValidationCaches =
(PFN_vkMergeValidationCachesEXT)vk::GetDeviceProcAddr(m_device->device(), "vkMergeValidationCachesEXT");
VkValidationCacheCreateInfoEXT validationCacheCreateInfo = LvlInitStruct<VkValidationCacheCreateInfoEXT>();
validationCacheCreateInfo.initialDataSize = 0;
validationCacheCreateInfo.pInitialData = NULL;
validationCacheCreateInfo.flags = 0;
VkValidationCacheEXT validationCache = VK_NULL_HANDLE;
VkResult res = fpCreateValidationCache(m_device->device(), &validationCacheCreateInfo, nullptr, &validationCache);
ASSERT_VK_SUCCESS(res);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkMergeValidationCachesEXT-dstCache-01536");
res = fpMergeValidationCaches(m_device->device(), validationCache, 1, &validationCache);
m_errorMonitor->VerifyFound();
fpDestroyValidationCache(m_device->device(), validationCache, nullptr);
}
TEST_F(VkLayerTest, InvalidQueueFamilyIndex) {
// Miscellaneous queueFamilyIndex validation tests
bool get_physical_device_properties2 = InstanceExtensionSupported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
if (get_physical_device_properties2) {
m_instance_extension_names.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
}
ASSERT_NO_FATAL_FAILURE(Init());
ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
VkBufferCreateInfo buffCI = LvlInitStruct<VkBufferCreateInfo>();
buffCI.size = 1024;
buffCI.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
buffCI.queueFamilyIndexCount = 2;
// Introduce failure by specifying invalid queue_family_index
uint32_t qfi[2];
qfi[0] = 777;
qfi[1] = 0;
buffCI.pQueueFamilyIndices = qfi;
buffCI.sharingMode = VK_SHARING_MODE_CONCURRENT; // qfi only matters in CONCURRENT mode
const char *vuid = (get_physical_device_properties2) ? "VUID-VkBufferCreateInfo-sharingMode-01419"
: "VUID-VkBufferCreateInfo-sharingMode-01391";
// Test for queue family index out of range
CreateBufferTest(*this, &buffCI, vuid);
// Test for non-unique QFI in array
qfi[0] = 0;
CreateBufferTest(*this, &buffCI, vuid);
if (m_device->queue_props.size() > 2) {
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkQueueSubmit-pSubmits-04626");
// Create buffer shared to queue families 1 and 2, but submitted on queue family 0
buffCI.queueFamilyIndexCount = 2;
qfi[0] = 1;
qfi[1] = 2;
VkBufferObj ib;
ib.init(*m_device, buffCI);
m_commandBuffer->begin();
vk::CmdFillBuffer(m_commandBuffer->handle(), ib.handle(), 0, 16, 5);
m_commandBuffer->end();
m_commandBuffer->QueueCommandBuffer(false);
m_errorMonitor->VerifyFound();
}
// If there is more than one queue family, create a device with a single queue family, then create a buffer
// with SHARING_MODE_CONCURRENT that uses a non-device PDEV queue family.
uint32_t queue_count;
vk::GetPhysicalDeviceQueueFamilyProperties(gpu(), &queue_count, NULL);
std::vector<VkQueueFamilyProperties> queue_props;
queue_props.resize(queue_count);
vk::GetPhysicalDeviceQueueFamilyProperties(gpu(), &queue_count, queue_props.data());
if (queue_count < 3) {
GTEST_SKIP() << "Multiple queue families are required to run this test.";
}
std::vector<float> priorities(queue_props.at(0).queueCount, 1.0f);
VkDeviceQueueCreateInfo queue_info = LvlInitStruct<VkDeviceQueueCreateInfo>();
queue_info.queueFamilyIndex = 0;
queue_info.queueCount = queue_props.at(0).queueCount;
queue_info.pQueuePriorities = priorities.data();
VkDeviceCreateInfo dev_info = LvlInitStruct<VkDeviceCreateInfo>();
dev_info.queueCreateInfoCount = 1;
dev_info.pQueueCreateInfos = &queue_info;
dev_info.enabledLayerCount = 0;
dev_info.enabledExtensionCount = m_device_extension_names.size();
dev_info.ppEnabledExtensionNames = m_device_extension_names.data();
// Create a device with a single queue family
VkDevice second_device;
ASSERT_VK_SUCCESS(vk::CreateDevice(gpu(), &dev_info, nullptr, &second_device));
// Select Queue family for CONCURRENT buffer that is not owned by device
buffCI.queueFamilyIndexCount = 2;
qfi[1] = 2;
VkBuffer buffer = VK_NULL_HANDLE;
vk::CreateBuffer(second_device, &buffCI, NULL, &buffer);
vk::DestroyBuffer(second_device, buffer, nullptr);
vk::DestroyDevice(second_device, nullptr);
}
TEST_F(VkLayerTest, UnclosedAndDuplicateQueries) {
TEST_DESCRIPTION("End a command buffer with a query still in progress, create nested queries.");
ASSERT_NO_FATAL_FAILURE(Init());
VkQueue queue = VK_NULL_HANDLE;
vk::GetDeviceQueue(m_device->device(), m_device->graphics_queue_node_index_, 0, &queue);
VkQueryPoolCreateInfo query_pool_create_info = LvlInitStruct<VkQueryPoolCreateInfo>();
query_pool_create_info.queryType = VK_QUERY_TYPE_OCCLUSION;
query_pool_create_info.queryCount = 5;
vk_testing::QueryPool query_pool(*m_device, query_pool_create_info);
m_commandBuffer->begin();
vk::CmdResetQueryPool(m_commandBuffer->handle(), query_pool.handle(), 0, 5);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBeginQuery-queryPool-01922");
vk::CmdBeginQuery(m_commandBuffer->handle(), query_pool.handle(), 1, 0);
// Attempt to begin a query that has the same type as an active query
vk::CmdBeginQuery(m_commandBuffer->handle(), query_pool.handle(), 3, 0);
vk::CmdEndQuery(m_commandBuffer->handle(), query_pool.handle(), 1);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkEndCommandBuffer-commandBuffer-00061");
vk::CmdBeginQuery(m_commandBuffer->handle(), query_pool.handle(), 0, 0);
vk::EndCommandBuffer(m_commandBuffer->handle());
m_errorMonitor->VerifyFound();
}
TEST_F(VkLayerTest, StageMaskHost) {
TEST_DESCRIPTION("Test invalid usage of VK_PIPELINE_STAGE_HOST_BIT.");
ASSERT_NO_FATAL_FAILURE(Init());
ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
VkEventCreateInfo event_create_info = LvlInitStruct<VkEventCreateInfo>();
vk_testing::Event event(*m_device, event_create_info);
ASSERT_TRUE(event.initialized());
m_commandBuffer->begin();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdSetEvent-stageMask-01149");
vk::CmdSetEvent(m_commandBuffer->handle(), event.handle(), VK_PIPELINE_STAGE_HOST_BIT);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdResetEvent-stageMask-01153");
vk::CmdResetEvent(m_commandBuffer->handle(), event.handle(), VK_PIPELINE_STAGE_HOST_BIT);
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
VkSemaphoreCreateInfo semaphore_create_info = LvlInitStruct<VkSemaphoreCreateInfo>();
vk_testing::Semaphore semaphore(*m_device, semaphore_create_info);
ASSERT_TRUE(semaphore.initialized());
VkPipelineStageFlags stage_flags = VK_PIPELINE_STAGE_HOST_BIT;
VkSubmitInfo submit_info = LvlInitStruct<VkSubmitInfo>();
// Signal the semaphore so the next test can wait on it.
submit_info.signalSemaphoreCount = 1;
submit_info.pSignalSemaphores = &semaphore.handle();
vk::QueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE);
submit_info.signalSemaphoreCount = 0;
submit_info.pSignalSemaphores = nullptr;
submit_info.waitSemaphoreCount = 1;
submit_info.pWaitSemaphores = &semaphore.handle();
submit_info.pWaitDstStageMask = &stage_flags;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkSubmitInfo-pWaitDstStageMask-00078");
vk::QueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE);
m_errorMonitor->VerifyFound();
// Need to ensure semaphore is not in use before the test ends and it gets destroyed
vk::QueueWaitIdle(m_device->m_queue);
}
#if GTEST_IS_THREADSAFE
TEST_F(VkLayerTest, ThreadCommandBufferCollision) {
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "THREADING ERROR");
m_errorMonitor->SetAllowedFailureMsg("THREADING ERROR"); // Ignore any extra threading errors found beyond the first one
ASSERT_NO_FATAL_FAILURE(Init());
ASSERT_NO_FATAL_FAILURE(InitViewport());
ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
// Test takes magnitude of time longer for profiles and slows down testing
if (IsPlatform(kMockICD)) {
GTEST_SKIP() << "Test not supported by MockICD";
}
// Calls AllocateCommandBuffers
VkCommandBufferObj commandBuffer(m_device, m_commandPool);
commandBuffer.begin();
VkEventCreateInfo event_info = LvlInitStruct<VkEventCreateInfo>();
vk_testing::Event event(*m_device, event_info);
VkResult err;
err = vk::ResetEvent(device(), event.handle());
ASSERT_VK_SUCCESS(err);
ThreadTestData data;
data.commandBuffer = commandBuffer.handle();
data.event = event.handle();
std::atomic<bool> bailout{false};
data.bailout = &bailout;
m_errorMonitor->SetBailout(data.bailout);
// First do some correct operations using multiple threads.
// Add many entries to command buffer from another thread.
std::thread thread1(AddToCommandBuffer, &data);
// Make non-conflicting calls from this thread at the same time.
for (int i = 0; i < 80000; i++) {
uint32_t count;
vk::EnumeratePhysicalDevices(instance(), &count, NULL);
}
thread1.join();
// Then do some incorrect operations using multiple threads.
// Add many entries to command buffer from another thread.
std::thread thread2(AddToCommandBuffer, &data);
// Add many entries to command buffer from this thread at the same time.
AddToCommandBuffer(&data);
thread2.join();
commandBuffer.end();
m_errorMonitor->SetBailout(NULL);
m_errorMonitor->VerifyFound();
}
TEST_F(VkLayerTest, ThreadUpdateDescriptorCollision) {
TEST_DESCRIPTION("Two threads updating the same descriptor set, expected to generate a threading error");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "THREADING ERROR : vkUpdateDescriptorSets");
m_errorMonitor->SetAllowedFailureMsg("THREADING ERROR"); // Ignore any extra threading errors found beyond the first one
ASSERT_NO_FATAL_FAILURE(Init());
ASSERT_NO_FATAL_FAILURE(InitViewport());
ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
OneOffDescriptorSet normal_descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr},
{1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr},
},
0);
VkBufferObj buffer;
buffer.init(*m_device, 256, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
ThreadTestData data;
data.device = device();
data.descriptorSet = normal_descriptor_set.set_;
data.binding = 0;
data.buffer = buffer.handle();
std::atomic<bool> bailout{false};
data.bailout = &bailout;
m_errorMonitor->SetBailout(data.bailout);
// Update descriptors from another thread.
std::thread thread(UpdateDescriptor, &data);
// Update descriptors from this thread at the same time.
ThreadTestData data2;
data2.device = device();
data2.descriptorSet = normal_descriptor_set.set_;
data2.binding = 1;
data2.buffer = buffer.handle();
data2.bailout = &bailout;
UpdateDescriptor(&data2);
thread.join();
m_errorMonitor->SetBailout(NULL);
m_errorMonitor->VerifyFound();
}
TEST_F(VkLayerTest, ThreadUpdateDescriptorUpdateAfterBindNoCollision) {
TEST_DESCRIPTION("Two threads updating the same UAB descriptor set, expected not to generate a threading error");
AddRequiredExtensions(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_MAINTENANCE_3_EXTENSION_NAME);
ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor));
if (!AreRequiredExtensionsEnabled()) {
GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported";
}
// Create a device that enables descriptorBindingStorageBufferUpdateAfterBind
auto indexing_features = LvlInitStruct<VkPhysicalDeviceDescriptorIndexingFeaturesEXT>();
auto features2 = GetPhysicalDeviceFeatures2(indexing_features);
if (VK_FALSE == indexing_features.descriptorBindingStorageBufferUpdateAfterBind) {
GTEST_SKIP() << "Test requires (unsupported) descriptorBindingStorageBufferUpdateAfterBind";
}
ASSERT_NO_FATAL_FAILURE(InitState(nullptr, &features2, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT));
ASSERT_NO_FATAL_FAILURE(InitViewport());
ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
std::array<VkDescriptorBindingFlagsEXT, 2> flags = {
{VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT, VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT}};
auto flags_create_info = LvlInitStruct<VkDescriptorSetLayoutBindingFlagsCreateInfoEXT>();
flags_create_info.bindingCount = (uint32_t)flags.size();
flags_create_info.pBindingFlags = flags.data();
OneOffDescriptorSet normal_descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr},
{1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr},
},
VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT, &flags_create_info,
VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT);
VkBufferObj buffer;
buffer.init(*m_device, 256, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
ThreadTestData data;
data.device = device();
data.descriptorSet = normal_descriptor_set.set_;
data.binding = 0;
data.buffer = buffer.handle();
std::atomic<bool> bailout{false};
data.bailout = &bailout;
m_errorMonitor->SetBailout(data.bailout);
// Update descriptors from another thread.
std::thread thread(UpdateDescriptor, &data);
// Update descriptors from this thread at the same time.
ThreadTestData data2;
data2.device = device();
data2.descriptorSet = normal_descriptor_set.set_;
data2.binding = 1;
data2.buffer = buffer.handle();
data2.bailout = &bailout;
UpdateDescriptor(&data2);
thread.join();
m_errorMonitor->SetBailout(NULL);
}
#endif // GTEST_IS_THREADSAFE
TEST_F(VkLayerTest, ExecuteUnrecordedCB) {
TEST_DESCRIPTION("Attempt vkQueueSubmit with a CB in the initial state");
ASSERT_NO_FATAL_FAILURE(Init());
// never record m_commandBuffer
VkSubmitInfo si = LvlInitStruct<VkSubmitInfo>();
si.commandBufferCount = 1;
si.pCommandBuffers = &m_commandBuffer->handle();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkQueueSubmit-pCommandBuffers-00070");
vk::QueueSubmit(m_device->m_queue, 1, &si, VK_NULL_HANDLE);
m_errorMonitor->VerifyFound();
// Testing an "unfinished secondary CB" crashes on some HW/drivers (notably Pixel 3 and RADV)
// VkCommandBufferObj cb(m_device, m_commandPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
// m_commandBuffer->begin();
// vk::CmdExecuteCommands(m_commandBuffer->handle(), 1u, &cb.handle());
// m_commandBuffer->end();
// m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkQueueSubmit-pCommandBuffers-00072");
// vk::QueueSubmit(m_device->m_queue, 1, &si, VK_NULL_HANDLE);
// m_errorMonitor->VerifyFound();
}
TEST_F(VkLayerTest, Maintenance1AndNegativeViewport) {
TEST_DESCRIPTION("Attempt to enable AMD_negative_viewport_height and Maintenance1_KHR extension simultaneously");
ASSERT_NO_FATAL_FAILURE(InitFramework());
if (!((DeviceExtensionSupported(gpu(), nullptr, VK_KHR_MAINTENANCE_1_EXTENSION_NAME)) &&
(DeviceExtensionSupported(gpu(), nullptr, VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_EXTENSION_NAME)))) {
GTEST_SKIP() << "Maintenance1 and AMD_negative viewport height extensions not supported";
}
ASSERT_NO_FATAL_FAILURE(InitState());
vk_testing::QueueCreateInfoArray queue_info(m_device->queue_props);
const char *extension_names[2] = {"VK_KHR_maintenance1", "VK_AMD_negative_viewport_height"};
VkDevice testDevice;
VkDeviceCreateInfo device_create_info = LvlInitStruct<VkDeviceCreateInfo>();
auto features = m_device->phy().features();
device_create_info.queueCreateInfoCount = queue_info.size();
device_create_info.pQueueCreateInfos = queue_info.data();
device_create_info.enabledLayerCount = 0;
device_create_info.ppEnabledLayerNames = NULL;
device_create_info.enabledExtensionCount = 2;
device_create_info.ppEnabledExtensionNames = (const char *const *)extension_names;
device_create_info.pEnabledFeatures = &features;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-00374");
// The following unexpected error is coming from the LunarG loader. Do not make it a desired message because platforms that do
// not use the LunarG loader (e.g. Android) will not see the message and the test will fail.
m_errorMonitor->SetUnexpectedError("Failed to create device chain.");
vk::CreateDevice(gpu(), &device_create_info, NULL, &testDevice);
m_errorMonitor->VerifyFound();
}
TEST_F(VkLayerTest, ApiVersion1_1AndNegativeViewport) {
TEST_DESCRIPTION("Attempt to enable AMD_negative_viewport_height with api version 1.1");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_EXTENSION_NAME);
ASSERT_NO_FATAL_FAILURE(InitFramework());
if (!AreRequiredExtensionsEnabled()) {
GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported";
}
if (DeviceValidationVersion() < VK_API_VERSION_1_1) {
GTEST_SKIP() << "At least Vulkan version 1.1 is required";
}
vk_testing::PhysicalDevice physical_device(gpu_);
VkPhysicalDeviceFeatures features = physical_device.features();
vk_testing::QueueCreateInfoArray queue_info(physical_device.queue_properties());
const char *extension_names[1] = {VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_EXTENSION_NAME};
VkDevice testDevice;
VkDeviceCreateInfo device_create_info = LvlInitStruct<VkDeviceCreateInfo>();
device_create_info.queueCreateInfoCount = queue_info.size();
device_create_info.pQueueCreateInfos = queue_info.data();
device_create_info.enabledLayerCount = 0;
device_create_info.ppEnabledLayerNames = NULL;
device_create_info.enabledExtensionCount = 1;
device_create_info.ppEnabledExtensionNames = (const char *const *)extension_names;
device_create_info.pEnabledFeatures = &features;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-01840");
// The following unexpected error is coming from the LunarG loader. Do not make it a desired message because platforms that do
// not use the LunarG loader (e.g. Android) will not see the message and the test will fail.
m_errorMonitor->SetUnexpectedError("Failed to create device chain.");
vk::CreateDevice(gpu(), &device_create_info, NULL, &testDevice);
m_errorMonitor->VerifyFound();
}
TEST_F(VkLayerTest, ResetEventThenSet) {
TEST_DESCRIPTION("Reset an event then set it after the reset has been submitted.");
ASSERT_NO_FATAL_FAILURE(Init());
VkEventCreateInfo event_create_info = LvlInitStruct<VkEventCreateInfo>();
vk_testing::Event event(*m_device, event_create_info);
VkCommandPoolCreateInfo pool_create_info = LvlInitStruct<VkCommandPoolCreateInfo>();
pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_;
pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
vk_testing::CommandPool command_pool(*m_device, pool_create_info);
VkCommandBuffer command_buffer;
VkCommandBufferAllocateInfo command_buffer_allocate_info = LvlInitStruct<VkCommandBufferAllocateInfo>();
command_buffer_allocate_info.commandPool = command_pool.handle();
command_buffer_allocate_info.commandBufferCount = 1;
command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
vk::AllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, &command_buffer);
VkQueue queue = VK_NULL_HANDLE;
vk::GetDeviceQueue(m_device->device(), m_device->graphics_queue_node_index_, 0, &queue);
{
VkCommandBufferBeginInfo begin_info = LvlInitStruct<VkCommandBufferBeginInfo>();
vk::BeginCommandBuffer(command_buffer, &begin_info);
vk::CmdResetEvent(command_buffer, event.handle(), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
vk::EndCommandBuffer(command_buffer);
}
{
VkSubmitInfo submit_info = LvlInitStruct<VkSubmitInfo>();
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &command_buffer;
submit_info.signalSemaphoreCount = 0;
submit_info.pSignalSemaphores = nullptr;
vk::QueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE);
}
{
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "that is already in use by a command buffer.");
vk::SetEvent(m_device->device(), event.handle());
m_errorMonitor->VerifyFound();
}
vk::QueueWaitIdle(queue);
vk::FreeCommandBuffers(m_device->device(), command_pool.handle(), 1, &command_buffer);
}
TEST_F(VkLayerTest, ValidateStride) {
TEST_DESCRIPTION("Validate Stride.");
ASSERT_NO_FATAL_FAILURE(Init(nullptr, nullptr, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT));
if (IsPlatform(kPixelC)) {
GTEST_SKIP() << "This test should not run on Pixel C";
}
uint32_t queue_count;
vk::GetPhysicalDeviceQueueFamilyProperties(gpu(), &queue_count, nullptr);
std::vector<VkQueueFamilyProperties> queue_props(queue_count);
vk::GetPhysicalDeviceQueueFamilyProperties(gpu(), &queue_count, queue_props.data());
if (queue_props[m_device->graphics_queue_node_index_].timestampValidBits == 0) {
GTEST_SKIP() << " Device graphic queue has timestampValidBits of 0, skipping.";
}
ASSERT_NO_FATAL_FAILURE(InitViewport());
ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
VkQueryPoolCreateInfo query_pool_ci = LvlInitStruct<VkQueryPoolCreateInfo>();
query_pool_ci.queryType = VK_QUERY_TYPE_TIMESTAMP;
query_pool_ci.queryCount = 1;
vk_testing::QueryPool query_pool(*m_device, query_pool_ci);
m_commandBuffer->begin();
vk::CmdResetQueryPool(m_commandBuffer->handle(), query_pool.handle(), 0, 1);
vk::CmdWriteTimestamp(m_commandBuffer->handle(), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, query_pool.handle(), 0);
m_commandBuffer->end();
VkSubmitInfo submit_info = LvlInitStruct<VkSubmitInfo>();
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &m_commandBuffer->handle();
vk::QueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE);
vk::QueueWaitIdle(m_device->m_queue);
char data_space;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkGetQueryPoolResults-flags-02827");
vk::GetQueryPoolResults(m_device->handle(), query_pool.handle(), 0, 1, sizeof(data_space), &data_space, 1,
VK_QUERY_RESULT_WAIT_BIT);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkGetQueryPoolResults-flags-00815");
vk::GetQueryPoolResults(m_device->handle(), query_pool.handle(), 0, 1, sizeof(data_space), &data_space, 1,
(VK_QUERY_RESULT_WAIT_BIT | VK_QUERY_RESULT_64_BIT));
m_errorMonitor->VerifyFound();
char data_space4[4] = "";
vk::GetQueryPoolResults(m_device->handle(), query_pool.handle(), 0, 1, sizeof(data_space4), &data_space4, 4,
VK_QUERY_RESULT_WAIT_BIT);
char data_space8[8] = "";
vk::GetQueryPoolResults(m_device->handle(), query_pool.handle(), 0, 1, sizeof(data_space8), &data_space8, 8,
(VK_QUERY_RESULT_WAIT_BIT | VK_QUERY_RESULT_64_BIT));
uint32_t qfi = 0;
VkBufferCreateInfo buff_create_info = LvlInitStruct<VkBufferCreateInfo>();
buff_create_info.size = 128;
buff_create_info.usage =
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
buff_create_info.queueFamilyIndexCount = 1;
buff_create_info.pQueueFamilyIndices = &qfi;
VkBufferObj buffer;
buffer.init(*m_device, buff_create_info);
m_commandBuffer->reset();
m_commandBuffer->begin();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdCopyQueryPoolResults-flags-00822");
vk::CmdCopyQueryPoolResults(m_commandBuffer->handle(), query_pool.handle(), 0, 1, buffer.handle(), 1, 1, 0);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdCopyQueryPoolResults-flags-00823");
vk::CmdCopyQueryPoolResults(m_commandBuffer->handle(), query_pool.handle(), 0, 1, buffer.handle(), 1, 1,
VK_QUERY_RESULT_64_BIT);
m_errorMonitor->VerifyFound();
vk::CmdCopyQueryPoolResults(m_commandBuffer->handle(), query_pool.handle(), 0, 1, buffer.handle(), 4, 4, 0);
vk::CmdCopyQueryPoolResults(m_commandBuffer->handle(), query_pool.handle(), 0, 1, buffer.handle(), 8, 8,
VK_QUERY_RESULT_64_BIT);
if (m_device->phy().features().multiDrawIndirect) {
auto buffer_memory_barrier = buffer.buffer_memory_barrier(
VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_INDIRECT_COMMAND_READ_BIT | VK_ACCESS_INDEX_READ_BIT, 0, VK_WHOLE_SIZE);
m_commandBuffer->PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT | VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, 0, nullptr, 1,
&buffer_memory_barrier, 0, nullptr);
CreatePipelineHelper helper(*this);
helper.InitInfo();
helper.InitState();
helper.CreateGraphicsPipeline();
m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo);
vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, helper.pipeline_);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDrawIndirect-drawCount-00476");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDrawIndirect-drawCount-00488");
vk::CmdDrawIndirect(m_commandBuffer->handle(), buffer.handle(), 0, 100, 2);
m_errorMonitor->VerifyFound();
vk::CmdDrawIndirect(m_commandBuffer->handle(), buffer.handle(), 0, 2, 24);
vk::CmdBindIndexBuffer(m_commandBuffer->handle(), buffer.handle(), 0, VK_INDEX_TYPE_UINT16);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDrawIndexedIndirect-drawCount-00528");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDrawIndexedIndirect-drawCount-00540");
vk::CmdDrawIndexedIndirect(m_commandBuffer->handle(), buffer.handle(), 0, 100, 2);
m_errorMonitor->VerifyFound();
auto draw_count = m_device->phy().properties().limits.maxDrawIndirectCount;
if (draw_count != vvl::kU32Max) {
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDrawIndirect-drawCount-02719");
vk::CmdDrawIndirect(m_commandBuffer->handle(), buffer.handle(), 0, draw_count + 1, 2);
m_errorMonitor->VerifyFound();
}
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDrawIndirect-drawCount-00487");
vk::CmdDrawIndirect(m_commandBuffer->handle(), buffer.handle(), buff_create_info.size, 1, 2);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdDrawIndexedIndirect-drawCount-00539");
vk::CmdDrawIndexedIndirect(m_commandBuffer->handle(), buffer.handle(), buff_create_info.size, 1, 2);
m_errorMonitor->VerifyFound();
vk::CmdDrawIndexedIndirect(m_commandBuffer->handle(), buffer.handle(), 0, 2, 24);
vk::CmdEndRenderPass(m_commandBuffer->handle());
m_commandBuffer->end();
} else {
printf("Test requires unsupported multiDrawIndirect feature. Skipped.\n");
}
}
TEST_F(VkLayerTest, ValidateNVDeviceDiagnosticCheckpoints) {
TEST_DESCRIPTION("General testing of VK_NV_device_diagnostic_checkpoints");
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
AddRequiredExtensions(VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_EXTENSION_NAME);
ASSERT_NO_FATAL_FAILURE(InitFramework());
if (!AreRequiredExtensionsEnabled()) {
GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported";
}
ASSERT_NO_FATAL_FAILURE(InitState());
auto vkGetQueueCheckpointDataNV =
(PFN_vkGetQueueCheckpointDataNV)vk::GetDeviceProcAddr(m_device->device(), "vkGetQueueCheckpointDataNV");
auto vkCmdSetCheckpointNV = (PFN_vkCmdSetCheckpointNV)vk::GetDeviceProcAddr(m_device->device(), "vkCmdSetCheckpointNV");
ASSERT_TRUE(vkGetQueueCheckpointDataNV != nullptr);
ASSERT_TRUE(vkCmdSetCheckpointNV != nullptr);
uint32_t data = 100;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdSetCheckpointNV-commandBuffer-recording");
vkCmdSetCheckpointNV(m_commandBuffer->handle(), &data);
m_errorMonitor->VerifyFound();
}
TEST_F(VkLayerTest, UniqueQueueDeviceCreation) {
TEST_DESCRIPTION("Vulkan 1.0 unique queue detection");
SetTargetApiVersion(VK_API_VERSION_1_0);
ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor));
// use first queue family with at least 2 queues in it
bool found_queue = false;
VkQueueFamilyProperties queue_properties; // selected queue family used
uint32_t queue_family_index = 0;
uint32_t queue_family_count = 0;
vk::GetPhysicalDeviceQueueFamilyProperties(gpu(), &queue_family_count, nullptr);
std::vector<VkQueueFamilyProperties> queue_families(queue_family_count);
vk::GetPhysicalDeviceQueueFamilyProperties(gpu(), &queue_family_count, queue_families.data());
for (size_t i = 0; i < queue_families.size(); i++) {
if (queue_families[i].queueCount > 1) {
found_queue = true;
queue_family_index = i;
queue_properties = queue_families[i];
break;
}
}
if (found_queue == false) {
GTEST_SKIP() << "test requires queue family with 2 queues, not available";
}
float queue_priority = 1.0;
VkDeviceQueueCreateInfo queue_create_info[2];
queue_create_info[0] = LvlInitStruct<VkDeviceQueueCreateInfo>();
queue_create_info[0].flags = 0;
queue_create_info[0].queueFamilyIndex = queue_family_index;
queue_create_info[0].queueCount = 1;
queue_create_info[0].pQueuePriorities = &queue_priority;
// queueFamilyIndex is the same
queue_create_info[1] = queue_create_info[0];
VkDevice test_device = VK_NULL_HANDLE;
VkDeviceCreateInfo device_create_info = LvlInitStruct<VkDeviceCreateInfo>();
device_create_info.flags = 0;
device_create_info.pQueueCreateInfos = queue_create_info;
device_create_info.queueCreateInfoCount = 2;
device_create_info.pEnabledFeatures = nullptr;
device_create_info.enabledLayerCount = 0;
device_create_info.enabledExtensionCount = 0;
const char *vuid = (DeviceValidationVersion() == VK_API_VERSION_1_0) ? "VUID-VkDeviceCreateInfo-queueFamilyIndex-00372"
: "VUID-VkDeviceCreateInfo-queueFamilyIndex-02802";
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, vuid);
vk::CreateDevice(gpu(), &device_create_info, nullptr, &test_device);
m_errorMonitor->VerifyFound();
}
template <typename ExtType, typename Parm>
void ExtendedDynStateCalls(ErrorMonitor *error_monitor, VkCommandBuffer cmd_buf, ExtType ext_call, const char *vuid, Parm parm) {
error_monitor->SetDesiredFailureMsg(kErrorBit, vuid);
ext_call(cmd_buf, parm);
error_monitor->VerifyFound();
}
TEST_F(VkLayerTest, ValidateArrayLength) {
TEST_DESCRIPTION("Validate arraylength VUs");
ASSERT_NO_FATAL_FAILURE(Init());
ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
// Used to have a valid pointed to set object too
VkCommandBuffer unused_command_buffer;
VkDescriptorSet unused_descriptor_set;
VkDescriptorSetObj descriptor_set_obj(m_device);
descriptor_set_obj.AppendDummy();
descriptor_set_obj.CreateVKDescriptorSet(m_commandBuffer);
VkDescriptorSet descriptor_set = descriptor_set_obj.GetDescriptorSetHandle();
VkFenceCreateInfo fence_create_info = LvlInitStruct<VkFenceCreateInfo>();
vk_testing::Fence fence(*m_device, fence_create_info);
VkEventCreateInfo event_create_info = LvlInitStruct<VkEventCreateInfo>();
vk_testing::Event event(*m_device, event_create_info);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkAllocateCommandBuffers-pAllocateInfo::commandBufferCount-arraylength");
{
VkCommandBufferAllocateInfo info = LvlInitStruct<VkCommandBufferAllocateInfo>();
info.commandPool = m_commandPool->handle();
info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
info.commandBufferCount = 0; // invalid
vk::AllocateCommandBuffers(device(), &info, &unused_command_buffer);
}
m_errorMonitor->VerifyFound();
// One exception in spec where the size of a field is used in both the function call it and the struct
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkAllocateDescriptorSets-pAllocateInfo::descriptorSetCount-arraylength");
// TODO - Figure out why VUID-VkDescriptorSetAllocateInfo-descriptorSetCount-arraylength is not being generated, very low
// priority since it is already caught with the above implicit VU. There was an internal MR and WG decided to keep both
// len='descriptorSetCount' for anyone relying on it
m_errorMonitor->SetUnexpectedError("VUID_Undefined");
{
VkDescriptorSetLayout set_layout = descriptor_set_obj.GetDescriptorSetLayout();
VkDescriptorSetAllocateInfo info = LvlInitStruct<VkDescriptorSetAllocateInfo>();
info.descriptorPool = descriptor_set_obj.handle();
info.descriptorSetCount = 0; // invalid
info.pSetLayouts = &set_layout;
vk::AllocateDescriptorSets(device(), &info, &unused_descriptor_set);
}
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkFreeCommandBuffers-commandBufferCount-arraylength");
vk::FreeCommandBuffers(device(), m_commandPool->handle(), 0, &unused_command_buffer);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkFreeDescriptorSets-descriptorSetCount-arraylength");
vk::FreeDescriptorSets(device(), descriptor_set_obj.handle(), 0, &descriptor_set);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkResetFences-fenceCount-arraylength");
vk::ResetFences(device(), 0, &fence.handle());
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkWaitForFences-fenceCount-arraylength");
vk::WaitForFences(device(), 0, &fence.handle(), true, 1);
m_errorMonitor->VerifyFound();
VkCommandBufferObj command_buffer(m_device, m_commandPool);
command_buffer.begin();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdBindDescriptorSets-descriptorSetCount-arraylength");
vk::CmdBindDescriptorSets(command_buffer.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, descriptor_set_obj.GetPipelineLayout(), 0,
0, &(descriptor_set), 0, nullptr);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdExecuteCommands-commandBufferCount-arraylength");
vk::CmdExecuteCommands(command_buffer.handle(), 0, &unused_command_buffer);
m_errorMonitor->VerifyFound();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdWaitEvents-eventCount-arraylength");
vk::CmdWaitEvents(command_buffer.handle(), 0, &event.handle(), VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
0, nullptr, 0, nullptr, 0, nullptr);
m_errorMonitor->VerifyFound();
command_buffer.end();
}
TEST_F(VkLayerTest, InvalidSpirvExtension) {
TEST_DESCRIPTION("Use an invalid SPIR-V extension in OpExtension.");
SetTargetApiVersion(VK_API_VERSION_1_2);
ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor));
if (DeviceValidationVersion() < VK_API_VERSION_1_2) {
GTEST_SKIP() << "At least Vulkan version 1.2 is required";
}
ASSERT_NO_FATAL_FAILURE(InitState());
ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
const char *vertex_source = R"spirv(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %4 "main"
OpSource GLSL 450
OpExtension "GL_EXT_scalar_block_layout"
OpName %4 "main"
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%4 = OpFunction %2 None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)spirv";
VkShaderObj vs(this, vertex_source, VK_SHADER_STAGE_VERTEX_BIT, SPV_ENV_VULKAN_1_2, SPV_SOURCE_ASM_TRY);
m_errorMonitor->SetUnexpectedError("VUID-VkShaderModuleCreateInfo-pCode-01379");
if (!vs.InitFromASMTry()) {
GTEST_SKIP() << "Failed to compile shader";
}
const VkShaderObj fs(this, bindStateFragShaderText, VK_SHADER_STAGE_FRAGMENT_BIT);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkShaderModuleCreateInfo-pCode-08741");
CreatePipelineHelper pipe(*this);
pipe.InitInfo();
pipe.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.InitState();
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(VkLayerTest, ValidateViewportStateScissorOverflow) {
TEST_DESCRIPTION("Validate sum of offset and width of viewport state scissor");
ASSERT_NO_FATAL_FAILURE(Init());
ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
VkViewport viewport = {0.0f, 0.0f, 64.0f, 64.0f, 0.0f, 1.0f};
VkRect2D scissor_x = {{vvl::kI32Max / 2, 0}, {vvl::kI32Max / 2 + 64, 64}};
VkRect2D scissor_y = {{0, vvl::kI32Max / 2}, {64, vvl::kI32Max / 2 + 64}};
const auto break_vp_x = [&](CreatePipelineHelper &helper) {
helper.vp_state_ci_.viewportCount = 1;
helper.vp_state_ci_.pViewports = &viewport;
helper.vp_state_ci_.scissorCount = 1;
helper.vp_state_ci_.pScissors = &scissor_x;
};
CreatePipelineHelper::OneshotTest(*this, break_vp_x, kErrorBit,
vector<std::string>({"VUID-VkPipelineViewportStateCreateInfo-offset-02822"}));
const auto break_vp_y = [&](CreatePipelineHelper &helper) {
helper.vp_state_ci_.viewportCount = 1;
helper.vp_state_ci_.pViewports = &viewport;
helper.vp_state_ci_.scissorCount = 1;
helper.vp_state_ci_.pScissors = &scissor_y;
};
CreatePipelineHelper::OneshotTest(*this, break_vp_y, kErrorBit,
vector<std::string>({"VUID-VkPipelineViewportStateCreateInfo-offset-02823"}));
}
TEST_F(VkLayerTest, ValidateViewportStateScissorNegative) {
TEST_DESCRIPTION("Validate offset of viewport state scissor");
ASSERT_NO_FATAL_FAILURE(Init());
ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
VkViewport viewport = {0.0f, 0.0f, 64.0f, 64.0f, 0.0f, 1.0f};
VkRect2D scissor_x = {{-64, 0}, {256, 256}};
VkRect2D scissor_y = {{0, -64}, {256, 256}};
const auto break_vp_x = [&](CreatePipelineHelper &helper) {
helper.vp_state_ci_.viewportCount = 1;
helper.vp_state_ci_.pViewports = &viewport;
helper.vp_state_ci_.scissorCount = 1;
helper.vp_state_ci_.pScissors = &scissor_x;
};
CreatePipelineHelper::OneshotTest(*this, break_vp_x, kErrorBit, "VUID-VkPipelineViewportStateCreateInfo-x-02821");
const auto break_vp_y = [&](CreatePipelineHelper &helper) {
helper.vp_state_ci_.viewportCount = 1;
helper.vp_state_ci_.pViewports = &viewport;
helper.vp_state_ci_.scissorCount = 1;
helper.vp_state_ci_.pScissors = &scissor_y;
};
CreatePipelineHelper::OneshotTest(*this, break_vp_y, kErrorBit, "VUID-VkPipelineViewportStateCreateInfo-x-02821");
}
TEST_F(VkLayerTest, DuplicatePhysicalDevices) {
TEST_DESCRIPTION("Duplicated physical devices in DeviceGroupDeviceCreateInfo.");
SetTargetApiVersion(VK_API_VERSION_1_1);
ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor));
uint32_t physical_device_group_count = 0;
vk::EnumeratePhysicalDeviceGroups(instance(), &physical_device_group_count, nullptr);
if (physical_device_group_count == 0) {
GTEST_SKIP() << "physical_device_group_count is 0";
}
std::vector<VkPhysicalDeviceGroupProperties> physical_device_group(physical_device_group_count,
{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES});
vk::EnumeratePhysicalDeviceGroups(instance(), &physical_device_group_count, physical_device_group.data());
VkPhysicalDevice physicalDevices[2] = {physical_device_group[0].physicalDevices[0],
physical_device_group[0].physicalDevices[0]};
VkDeviceGroupDeviceCreateInfo create_device_pnext = LvlInitStruct<VkDeviceGroupDeviceCreateInfo>();
create_device_pnext.physicalDeviceCount = 2;
create_device_pnext.pPhysicalDevices = physicalDevices;
ASSERT_NO_FATAL_FAILURE(InitState());
vk_testing::QueueCreateInfoArray queue_info(m_device->queue_props);
VkDeviceCreateInfo create_info = LvlInitStruct<VkDeviceCreateInfo>();
create_info.pNext = &create_device_pnext;
create_info.queueCreateInfoCount = queue_info.size();
create_info.pQueueCreateInfos = queue_info.data();
create_info.enabledLayerCount = 0;
create_info.ppEnabledLayerNames = nullptr;
create_info.enabledExtensionCount = m_device_extension_names.size();
create_info.ppEnabledExtensionNames = m_device_extension_names.data();
VkDevice device;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkDeviceGroupDeviceCreateInfo-pPhysicalDevices-00375");
vk::CreateDevice(gpu(), &create_info, nullptr, &device);
m_errorMonitor->VerifyFound();
}
TEST_F(VkLayerTest, InvalidCombinationOfDeviceFeatures) {
TEST_DESCRIPTION("Test invalid combinations of device features.");
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT shader_image_atomic_int64_feature =
LvlInitStruct<VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT>();
shader_image_atomic_int64_feature.sparseImageInt64Atomics = VK_TRUE;
shader_image_atomic_int64_feature.shaderImageInt64Atomics = VK_FALSE;
VkPhysicalDeviceShaderAtomicFloatFeaturesEXT shader_atomic_float_feature =
LvlInitStruct<VkPhysicalDeviceShaderAtomicFloatFeaturesEXT>();
shader_atomic_float_feature.sparseImageFloat32Atomics = VK_TRUE;
shader_atomic_float_feature.shaderImageFloat32Atomics = VK_FALSE;
shader_atomic_float_feature.sparseImageFloat32AtomicAdd = VK_TRUE;
shader_atomic_float_feature.shaderImageFloat32AtomicAdd = VK_FALSE;
VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT shader_atomic_float_feature2 =
LvlInitStruct<VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT>();
shader_atomic_float_feature2.sparseImageFloat32AtomicMinMax = VK_TRUE;
shader_atomic_float_feature2.shaderImageFloat32AtomicMinMax = VK_FALSE;
VkPhysicalDeviceFeatures2 pd_features2 = LvlInitStruct<VkPhysicalDeviceFeatures2>(&shader_image_atomic_int64_feature);
ASSERT_NO_FATAL_FAILURE(Init());
if (!AreRequiredExtensionsEnabled()) {
GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported";
}
vk_testing::QueueCreateInfoArray queue_info(m_device->queue_props);
VkDeviceCreateInfo device_create_info = LvlInitStruct<VkDeviceCreateInfo>();
device_create_info.pNext = &pd_features2;
device_create_info.queueCreateInfoCount = queue_info.size();
device_create_info.pQueueCreateInfos = queue_info.data();
{
VkDevice testDevice;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkDeviceCreateInfo-None-04896");
vk::CreateDevice(gpu(), &device_create_info, NULL, &testDevice);
m_errorMonitor->VerifyFound();
}
{
pd_features2.pNext = &shader_atomic_float_feature;
VkDevice testDevice;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkDeviceCreateInfo-None-04897");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkDeviceCreateInfo-None-04898");
vk::CreateDevice(gpu(), &device_create_info, NULL, &testDevice);
m_errorMonitor->VerifyFound();
}
{
pd_features2.pNext = &shader_atomic_float_feature2;
VkDevice testDevice;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkDeviceCreateInfo-sparseImageFloat32AtomicMinMax-04975");
vk::CreateDevice(gpu(), &device_create_info, NULL, &testDevice);
m_errorMonitor->VerifyFound();
}
}
TEST_F(VkLayerTest, InvalidImageCreateFlagWithPhysicalDeviceCount) {
TEST_DESCRIPTION("Test for invalid imageCreate flags bit with physicalDeviceCount.");
SetTargetApiVersion(VK_API_VERSION_1_1);
ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor));
if (DeviceValidationVersion() < VK_API_VERSION_1_1) {
GTEST_SKIP() << "At least Vulkan version 1.1 is required";
}
uint32_t physical_device_group_count = 0;
vk::EnumeratePhysicalDeviceGroups(instance(), &physical_device_group_count, nullptr);
if (physical_device_group_count == 0) {
GTEST_SKIP() << "physical_device_group_count is 0";
}
std::vector<VkPhysicalDeviceGroupProperties> physical_device_group(physical_device_group_count,
{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES});
vk::EnumeratePhysicalDeviceGroups(instance(), &physical_device_group_count, physical_device_group.data());
VkDeviceGroupDeviceCreateInfo create_device_pnext = LvlInitStruct<VkDeviceGroupDeviceCreateInfo>();
create_device_pnext.physicalDeviceCount = 1;
create_device_pnext.pPhysicalDevices = physical_device_group[0].physicalDevices;
ASSERT_NO_FATAL_FAILURE(InitState(nullptr, &create_device_pnext, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT));
VkImageCreateInfo ici = LvlInitStruct<VkImageCreateInfo>();
ici.flags = VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT;
ici.imageType = VK_IMAGE_TYPE_2D;
ici.arrayLayers = 1;
ici.extent = {64, 64, 1};
ici.format = VK_FORMAT_R8G8B8A8_UNORM;
ici.mipLevels = 1;
ici.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
ici.samples = VK_SAMPLE_COUNT_1_BIT;
ici.tiling = VK_IMAGE_TILING_OPTIMAL;
ici.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
VkImageFormatProperties imageFormatProperties;
VkResult result =
vk::GetPhysicalDeviceImageFormatProperties(physical_device_group[0].physicalDevices[0], ici.format, ici.imageType,
ici.tiling, ici.usage, ici.flags, &imageFormatProperties);
if (result == VK_ERROR_FORMAT_NOT_SUPPORTED) {
GTEST_SKIP() << "image format is not supported";
}
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkImageCreateInfo-physicalDeviceCount-01421");
VkImage test_image;
vk::CreateImage(device(), &ici, nullptr, &test_image);
m_errorMonitor->VerifyFound();
}
TEST_F(VkLayerTest, Features12AndppEnabledExtensionNames) {
TEST_DESCRIPTION("Test VkPhysicalDeviceVulkan12Features and illegal extension in ppEnabledExtensionNames");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
ASSERT_NO_FATAL_FAILURE(InitFramework());
if (!AreRequiredExtensionsEnabled()) {
GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported";
}
VkPhysicalDeviceVulkan12Features features12 = LvlInitStruct<VkPhysicalDeviceVulkan12Features>();
features12.bufferDeviceAddress = VK_TRUE;
float priority = 1.0f;
VkDeviceQueueCreateInfo queue_info = LvlInitStruct<VkDeviceQueueCreateInfo>();
queue_info.queueFamilyIndex = 0;
queue_info.queueCount = 1;
queue_info.pQueuePriorities = &priority;
const char *enabled_ext = VK_EXT_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME;
VkDeviceCreateInfo device_create_info = LvlInitStruct<VkDeviceCreateInfo>(&features12);
device_create_info.queueCreateInfoCount = 1;
device_create_info.pQueueCreateInfos = &queue_info;
device_create_info.enabledExtensionCount = 1;
device_create_info.ppEnabledExtensionNames = &enabled_ext;
VkDevice testDevice;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkDeviceCreateInfo-pNext-04748");
vk::CreateDevice(gpu(), &device_create_info, NULL, &testDevice);
m_errorMonitor->VerifyFound();
}
TEST_F(VkLayerTest, ImageSubresourceOverlapBetweenCurrentRenderPassAndDescriptorSets) {
TEST_DESCRIPTION("Validate if attachments in render pass and descriptor set use the same image subresources");
ASSERT_NO_FATAL_FAILURE(Init());
ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "UNASSIGNED-CoreValidation-DrawState-InvalidRenderpass");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkRenderPassBeginInfo-renderPass-00904");
const uint32_t width = 16;
const uint32_t height = 16;
const VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
VkAttachmentReference attach_ref = {};
attach_ref.attachment = 0;
attach_ref.layout = VK_IMAGE_LAYOUT_GENERAL;
VkSubpassDescription subpass = {};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &attach_ref;
VkAttachmentDescription attach_desc = {};
attach_desc.format = format;
attach_desc.samples = VK_SAMPLE_COUNT_1_BIT;
attach_desc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attach_desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attach_desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attach_desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attach_desc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attach_desc.finalLayout = VK_IMAGE_LAYOUT_GENERAL;
VkAttachmentDescription attach_desc2[] = {attach_desc, attach_desc};
VkRenderPassCreateInfo rpci = LvlInitStruct<VkRenderPassCreateInfo>();
rpci.subpassCount = 1;
rpci.pSubpasses = &subpass;
rpci.attachmentCount = 2;
rpci.pAttachments = attach_desc2;
vk_testing::RenderPass render_pass(*m_device, rpci);
VkClearValue clear_values[2] = {m_renderPassClearValues[0], m_renderPassClearValues[0]};
VkRenderPassBeginInfo rpbi = LvlInitStruct<VkRenderPassBeginInfo>();
rpbi.framebuffer = m_framebuffer;
rpbi.renderPass = render_pass.handle();
rpbi.renderArea.extent.width = width;
rpbi.renderArea.extent.height = height;
rpbi.clearValueCount = 2;
rpbi.pClearValues = clear_values;
m_commandBuffer->begin();
vk::CmdBeginRenderPass(m_commandBuffer->handle(), &rpbi, VK_SUBPASS_CONTENTS_INLINE);
m_commandBuffer->end();
m_errorMonitor->VerifyFound();
}
TEST_F(VkLayerTest, ZeroBitmask) {
TEST_DESCRIPTION("Test a reserved flags field set to a non-zero value");
ASSERT_NO_FATAL_FAILURE(Init());
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkSemaphoreCreateInfo-flags-zerobitmask");
auto semaphore_ci = LvlInitStruct<VkSemaphoreCreateInfo>();
semaphore_ci.flags = 1;
VkSemaphore semaphore = VK_NULL_HANDLE;
vk::CreateSemaphore(m_device->device(), &semaphore_ci, nullptr, &semaphore);
m_errorMonitor->VerifyFound();
}
TEST_F(VkLayerTest, InvalidDeviceQueueFamilyIndex) {
TEST_DESCRIPTION("Create device queue with invalid queue family index.");
ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor));
uint32_t queue_family_count;
vk::GetPhysicalDeviceQueueFamilyProperties(gpu(), &queue_family_count, nullptr);
std::vector<VkQueueFamilyProperties> queue_props(queue_family_count);
vk::GetPhysicalDeviceQueueFamilyProperties(gpu(), &queue_family_count, queue_props.data());
uint32_t queue_family_index = queue_family_count;
float priority = 1.0f;
auto device_queue_ci = LvlInitStruct<VkDeviceQueueCreateInfo>();
device_queue_ci.queueFamilyIndex = queue_family_index;
device_queue_ci.queueCount = 1;
device_queue_ci.pQueuePriorities = &priority;
auto device_ci = LvlInitStruct<VkDeviceCreateInfo>();
device_ci.queueCreateInfoCount = 1;
device_ci.pQueueCreateInfos = &device_queue_ci;
device_ci.enabledLayerCount = 0;
device_ci.enabledExtensionCount = m_device_extension_names.size();
device_ci.ppEnabledExtensionNames = m_device_extension_names.data();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkDeviceQueueCreateInfo-queueFamilyIndex-00381");
VkDevice device;
vk::CreateDevice(gpu(), &device_ci, nullptr, &device);
m_errorMonitor->VerifyFound();
}
TEST_F(VkLayerTest, InstanceCreateEnumeratePortability) {
TEST_DESCRIPTION("Validate creating instances with VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR.");
auto ici = GetInstanceCreateInfo();
ici.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
VkInstance local_instance;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkInstanceCreateInfo-flags-06559");
vk::CreateInstance(&ici, nullptr, &local_instance);
m_errorMonitor->VerifyFound();
if (InstanceExtensionSupported(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME)) {
std::vector<const char *> enabled_extensions;
for (uint32_t i = 0; i < ici.enabledExtensionCount; ++i) {
enabled_extensions.push_back(ici.ppEnabledExtensionNames[i]);
}
enabled_extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
ici.enabledExtensionCount++;
ici.ppEnabledExtensionNames = enabled_extensions.data();
ASSERT_VK_SUCCESS(vk::CreateInstance(&ici, nullptr, &local_instance));
vk::DestroyInstance(local_instance, nullptr);
}
}
TEST_F(VkLayerTest, MismatchedDeviceQueueGlobalPriority) {
TEST_DESCRIPTION("Create multiple device queues with same queue family index but different global priorty.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_GLOBAL_PRIORITY_EXTENSION_NAME);
ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor));
if (DeviceValidationVersion() < VK_API_VERSION_1_1) {
GTEST_SKIP() << "At least Vulkan version 1.1 is required";
}
if (!AreRequiredExtensionsEnabled()) {
GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported";
}
uint32_t queue_family_count;
vk::GetPhysicalDeviceQueueFamilyProperties(gpu(), &queue_family_count, nullptr);
std::vector<VkQueueFamilyProperties> queue_props(queue_family_count);
vk::GetPhysicalDeviceQueueFamilyProperties(gpu(), &queue_family_count, queue_props.data());
uint32_t queue_family_index = queue_family_count;
for (uint32_t i = 0; i < queue_family_count; ++i) {
if (queue_props[i].queueCount > 1) {
queue_family_index = i;
break;
}
}
if (queue_family_index == queue_family_count) {
GTEST_SKIP() << "Multiple queues from same queue family are required to run this test";
}
VkDeviceQueueGlobalPriorityCreateInfoKHR queue_global_priority_ci[2] = {};
queue_global_priority_ci[0] = LvlInitStruct<VkDeviceQueueGlobalPriorityCreateInfoKHR>();
queue_global_priority_ci[0].globalPriority = VK_QUEUE_GLOBAL_PRIORITY_LOW_KHR;
queue_global_priority_ci[1] = LvlInitStruct<VkDeviceQueueGlobalPriorityCreateInfoKHR>();
queue_global_priority_ci[1].globalPriority = VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_KHR;
float priorities[] = {1.0f, 1.0f};
VkDeviceQueueCreateInfo device_queue_ci[2] = {};
device_queue_ci[0] = LvlInitStruct<VkDeviceQueueCreateInfo>(&queue_global_priority_ci[0]);
device_queue_ci[0].queueFamilyIndex = queue_family_index;
device_queue_ci[0].queueCount = 1;
device_queue_ci[0].pQueuePriorities = &priorities[0];
device_queue_ci[1] = LvlInitStruct<VkDeviceQueueCreateInfo>(&queue_global_priority_ci[1]);
device_queue_ci[1].queueFamilyIndex = queue_family_index;
device_queue_ci[1].queueCount = 1;
device_queue_ci[1].pQueuePriorities = &priorities[1];
auto device_ci = LvlInitStruct<VkDeviceCreateInfo>();
device_ci.queueCreateInfoCount = 2;
device_ci.pQueueCreateInfos = device_queue_ci;
device_ci.enabledLayerCount = 0;
device_ci.enabledExtensionCount = m_device_extension_names.size();
device_ci.ppEnabledExtensionNames = m_device_extension_names.data();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkDeviceCreateInfo-queueFamilyIndex-02802");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkDeviceCreateInfo-pQueueCreateInfos-06654");
VkDevice device;
vk::CreateDevice(gpu(), &device_ci, nullptr, &device);
m_errorMonitor->VerifyFound();
}
#ifdef VK_USE_PLATFORM_METAL_EXT
TEST_F(VkLayerTest, ExportMetalObjects) {
TEST_DESCRIPTION("Test VK_EXT_metal_objects VUIDs");
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_METAL_OBJECTS_EXTENSION_NAME);
AddOptionalExtensions(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
ASSERT_NO_FATAL_FAILURE(InitFramework());
if (!AreRequiredExtensionsEnabled()) {
GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported";
}
const bool ycbcr_conversion_extension = IsExtensionsEnabled(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
auto portability_features = LvlInitStruct<VkPhysicalDevicePortabilitySubsetFeaturesKHR>();
auto features2 = GetPhysicalDeviceFeatures2(portability_features);
if (ycbcr_conversion_extension) {
auto ycbcr_features = LvlInitStruct<VkPhysicalDeviceSamplerYcbcrConversionFeatures>();
ycbcr_features.samplerYcbcrConversion = VK_TRUE;
portability_features.pNext = &ycbcr_features;
}
ASSERT_NO_FATAL_FAILURE(InitState(nullptr, &features2));
PFN_vkExportMetalObjectsEXT vkExportMetalObjectsEXT =
reinterpret_cast<PFN_vkExportMetalObjectsEXT>(vk::GetDeviceProcAddr(m_device->device(), "vkExportMetalObjectsEXT"));
ASSERT_TRUE(vkExportMetalObjectsEXT != nullptr);
auto metal_object_create_info = LvlInitStruct<VkExportMetalObjectCreateInfoEXT>();
auto instance_ci = GetInstanceCreateInfo();
metal_object_create_info.exportObjectType = VK_EXPORT_METAL_OBJECT_TYPE_METAL_SHARED_EVENT_BIT_EXT;
metal_object_create_info.pNext = instance_ci.pNext;
instance_ci.pNext = &metal_object_create_info;
VkInstance instance = {};
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkInstanceCreateInfo-pNext-06779");
vk::CreateInstance(&instance_ci, nullptr, &instance);
m_errorMonitor->VerifyFound();
metal_object_create_info.pNext = nullptr;
auto alloc_info = LvlInitStruct<VkMemoryAllocateInfo>();
alloc_info.pNext = &metal_object_create_info;
alloc_info.allocationSize = 1024;
VkDeviceMemory memory;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkMemoryAllocateInfo-pNext-06780");
vk::AllocateMemory(device(), &alloc_info, nullptr, &memory);
m_errorMonitor->VerifyFound();
VkImageCreateInfo ici = LvlInitStruct<VkImageCreateInfo>();
ici.imageType = VK_IMAGE_TYPE_2D;
ici.format = VK_FORMAT_B8G8R8A8_UNORM;
ici.extent = {128, 128, 1};
ici.mipLevels = 1;
ici.arrayLayers = 1;
ici.samples = VK_SAMPLE_COUNT_1_BIT;
ici.tiling = VK_IMAGE_TILING_LINEAR;
ici.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
ici.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
ici.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
ici.pNext = &metal_object_create_info;
VkImage image;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkImageCreateInfo-pNext-06783");
vk::CreateImage(device(), &ici, NULL, &image);
m_errorMonitor->VerifyFound();
auto import_metal_texture_info = LvlInitStruct<VkImportMetalTextureInfoEXT>();
import_metal_texture_info.plane = VK_IMAGE_ASPECT_COLOR_BIT;
ici.pNext = &import_metal_texture_info;
ici.format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkImageCreateInfo-pNext-06784");
vk::CreateImage(device(), &ici, NULL, &image);
m_errorMonitor->VerifyFound();
ici.format = VK_FORMAT_B8G8R8A8_UNORM;
import_metal_texture_info.plane = VK_IMAGE_ASPECT_PLANE_1_BIT;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkImageCreateInfo-pNext-06785");
vk::CreateImage(device(), &ici, NULL, &image);
m_errorMonitor->VerifyFound();
ici.format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
import_metal_texture_info.plane = VK_IMAGE_ASPECT_PLANE_2_BIT;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkImageCreateInfo-pNext-06786");
vk::CreateImage(device(), &ici, NULL, &image);
m_errorMonitor->VerifyFound();
uint32_t queue_family_index = 0;
VkBufferCreateInfo buffer_create_info = LvlInitStruct<VkBufferCreateInfo>();
buffer_create_info.size = 1024;
buffer_create_info.usage = VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
buffer_create_info.queueFamilyIndexCount = 1;
buffer_create_info.pQueueFamilyIndices = &queue_family_index;
VkBufferObj buffer;
buffer.init(*m_device, buffer_create_info);
VkBufferViewCreateInfo buff_view_ci = LvlInitStruct<VkBufferViewCreateInfo>();
buff_view_ci.buffer = buffer.handle();
buff_view_ci.format = VK_FORMAT_B8G8R8A8_UNORM;
buff_view_ci.range = VK_WHOLE_SIZE;
VkBufferView buffer_view;
buff_view_ci.pNext = &metal_object_create_info;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkBufferViewCreateInfo-pNext-06782");
vk::CreateBufferView(device(), &buff_view_ci, NULL, &buffer_view);
m_errorMonitor->VerifyFound();
VkImageObj image_obj(m_device);
image_obj.Init(256, 256, 1, VK_FORMAT_B8G8R8A8_UNORM, VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_TILING_OPTIMAL, 0);
VkImageView image_view;
VkImageViewCreateInfo ivci = LvlInitStruct<VkImageViewCreateInfo>();
ivci.image = image_obj.handle();
ivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
ivci.format = VK_FORMAT_B8G8R8A8_UNORM;
ivci.subresourceRange.layerCount = 1;
ivci.subresourceRange.baseMipLevel = 0;
ivci.subresourceRange.levelCount = 1;
ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
ivci.pNext = &metal_object_create_info;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkImageViewCreateInfo-pNext-06787");
vk::CreateImageView(m_device->device(), &ivci, nullptr, &image_view);
m_errorMonitor->VerifyFound();
auto sem_info = LvlInitStruct<VkSemaphoreCreateInfo>();
sem_info.pNext = &metal_object_create_info;
VkSemaphore semaphore;
metal_object_create_info.exportObjectType = VK_EXPORT_METAL_OBJECT_TYPE_METAL_BUFFER_BIT_EXT;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkSemaphoreCreateInfo-pNext-06789");
vk::CreateSemaphore(device(), &sem_info, NULL, &semaphore);
m_errorMonitor->VerifyFound();
auto event_info = LvlInitStruct<VkEventCreateInfo>();
if (portability_features.events) {
event_info.pNext = &metal_object_create_info;
VkEvent event;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkEventCreateInfo-pNext-06790");
vk::CreateEvent(device(), &event_info, nullptr, &event);
m_errorMonitor->VerifyFound();
}
auto export_metal_objects_info = LvlInitStruct<VkExportMetalObjectsInfoEXT>();
auto metal_device_info = LvlInitStruct<VkExportMetalDeviceInfoEXT>();
auto metal_command_queue_info = LvlInitStruct<VkExportMetalCommandQueueInfoEXT>();
metal_command_queue_info.queue = m_device->m_queue;
export_metal_objects_info.pNext = &metal_device_info;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkExportMetalObjectsInfoEXT-pNext-06791");
vkExportMetalObjectsEXT(m_device->handle(), &export_metal_objects_info);
m_errorMonitor->VerifyFound();
export_metal_objects_info.pNext = &metal_command_queue_info;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkExportMetalObjectsInfoEXT-pNext-06792");
vkExportMetalObjectsEXT(m_device->handle(), &export_metal_objects_info);
m_errorMonitor->VerifyFound();
alloc_info.pNext = nullptr;
VkResult err = vk::AllocateMemory(device(), &alloc_info, nullptr, &memory);
ASSERT_VK_SUCCESS(err);
auto metal_buffer_info = LvlInitStruct<VkExportMetalBufferInfoEXT>();
metal_buffer_info.memory = memory;
export_metal_objects_info.pNext = &metal_buffer_info;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkExportMetalObjectsInfoEXT-pNext-06793");
vkExportMetalObjectsEXT(m_device->handle(), &export_metal_objects_info);
m_errorMonitor->VerifyFound();
vk::FreeMemory(device(), memory, nullptr);
auto export_metal_object_create_info = LvlInitStruct<VkExportMetalObjectCreateInfoEXT>();
export_metal_object_create_info.exportObjectType = VK_EXPORT_METAL_OBJECT_TYPE_METAL_TEXTURE_BIT_EXT;
ici.pNext = &export_metal_object_create_info;
VkImageObj export_image_obj(m_device);
export_image_obj.Init(ici);
vk_testing::BufferView export_buffer_view;
buff_view_ci.pNext = &export_metal_object_create_info;
export_buffer_view.init(*m_device, buff_view_ci);
auto metal_texture_info = LvlInitStruct<VkExportMetalTextureInfoEXT>();
metal_texture_info.bufferView = export_buffer_view.handle();
metal_texture_info.image = export_image_obj.handle();
metal_texture_info.plane = VK_IMAGE_ASPECT_PLANE_0_BIT;
export_metal_objects_info.pNext = &metal_texture_info;
// Only one of image, bufferView, imageView
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkExportMetalObjectsInfoEXT-pNext-06794");
vkExportMetalObjectsEXT(m_device->handle(), &export_metal_objects_info);
m_errorMonitor->VerifyFound();
// Image not created with struct in pNext
metal_texture_info.bufferView = VK_NULL_HANDLE;
metal_texture_info.image = image_obj.handle();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkExportMetalObjectsInfoEXT-pNext-06795");
vkExportMetalObjectsEXT(m_device->handle(), &export_metal_objects_info);
m_errorMonitor->VerifyFound();
metal_texture_info.image = VK_NULL_HANDLE;
vk_testing::ImageView image_view_no_struct;
auto image_view_ci = image_obj.TargetViewCI(VK_FORMAT_B8G8R8A8_UNORM);
image_view_ci.image = image_obj.handle();
image_view_no_struct.init(*m_device, image_view_ci);
metal_texture_info.imageView = image_view_no_struct.handle();
// ImageView not created with struct in pNext
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkExportMetalObjectsInfoEXT-pNext-06796");
vkExportMetalObjectsEXT(m_device->handle(), &export_metal_objects_info);
m_errorMonitor->VerifyFound();
buff_view_ci.pNext = nullptr;
vk_testing::BufferView buffer_view_no_struct;
buffer_view_no_struct.init(*m_device, buff_view_ci);
metal_texture_info.imageView = VK_NULL_HANDLE;
metal_texture_info.bufferView = buffer_view_no_struct.handle();
// BufferView not created with struct in pNext
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkExportMetalObjectsInfoEXT-pNext-06797");
vkExportMetalObjectsEXT(m_device->handle(), &export_metal_objects_info);
m_errorMonitor->VerifyFound();
metal_texture_info.bufferView = VK_NULL_HANDLE;
metal_texture_info.image = export_image_obj.handle();
metal_texture_info.plane = VK_IMAGE_ASPECT_COLOR_BIT;
// metal_texture_info.plane not plane 0, 1 or 2
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkExportMetalObjectsInfoEXT-pNext-06798");
vkExportMetalObjectsEXT(m_device->handle(), &export_metal_objects_info);
m_errorMonitor->VerifyFound();
ici.format = VK_FORMAT_B8G8R8A8_UNORM;
VkImageObj single_plane_export_image_obj(m_device);
single_plane_export_image_obj.Init(ici);
metal_texture_info.plane = VK_IMAGE_ASPECT_PLANE_1_BIT;
metal_texture_info.image = single_plane_export_image_obj.handle();
// metal_texture_info.plane not plane_0 for single plane image
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkExportMetalObjectsInfoEXT-pNext-06799");
vkExportMetalObjectsEXT(m_device->handle(), &export_metal_objects_info);
m_errorMonitor->VerifyFound();
image_view_ci.pNext = &export_metal_object_create_info;
export_metal_object_create_info.exportObjectType = VK_EXPORT_METAL_OBJECT_TYPE_METAL_TEXTURE_BIT_EXT;
vk_testing::ImageView single_plane_export_image_view;
single_plane_export_image_view.init(*m_device, image_view_ci);
metal_texture_info.image = VK_NULL_HANDLE;
metal_texture_info.imageView = single_plane_export_image_view.handle();
// metal_texture_info.plane not plane_0 for single plane imageView
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkExportMetalObjectsInfoEXT-pNext-06801");
vkExportMetalObjectsEXT(m_device->handle(), &export_metal_objects_info);
m_errorMonitor->VerifyFound();
auto metal_iosurface_info = LvlInitStruct<VkExportMetalIOSurfaceInfoEXT>();
metal_iosurface_info.image = image_obj.handle();
export_metal_objects_info.pNext = &metal_iosurface_info;
// metal_iosurface_info.image not created with struct in pNext
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkExportMetalObjectsInfoEXT-pNext-06803");
vkExportMetalObjectsEXT(m_device->handle(), &export_metal_objects_info);
m_errorMonitor->VerifyFound();
auto metal_shared_event_info = LvlInitStruct<VkExportMetalSharedEventInfoEXT>();
export_metal_objects_info.pNext = &metal_shared_event_info;
// metal_shared_event_info event and semaphore both VK_NULL_HANDLE
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkExportMetalObjectsInfoEXT-pNext-06804");
vkExportMetalObjectsEXT(m_device->handle(), &export_metal_objects_info);
m_errorMonitor->VerifyFound();
sem_info.pNext = nullptr;
vk_testing::Semaphore semaphore_no_struct;
semaphore_no_struct.init(*m_device, sem_info);
metal_shared_event_info.semaphore = semaphore_no_struct.handle();
export_metal_objects_info.pNext = &metal_shared_event_info;
// Semaphore not created with struct in pNext
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkExportMetalObjectsInfoEXT-pNext-06805");
vkExportMetalObjectsEXT(m_device->handle(), &export_metal_objects_info);
m_errorMonitor->VerifyFound();
if (portability_features.events) {
event_info.pNext = nullptr;
vk_testing::Event event_no_struct;
event_no_struct.init(*m_device, event_info);
metal_shared_event_info.event = event_no_struct.handle();
metal_shared_event_info.semaphore = VK_NULL_HANDLE;
// Event not created with struct in pNext
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkExportMetalObjectsInfoEXT-pNext-06806");
vkExportMetalObjectsEXT(m_device->handle(), &export_metal_objects_info);
m_errorMonitor->VerifyFound();
}
const VkFormat mp_format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
if (ImageFormatIsSupported(gpu(), mp_format)) {
export_metal_object_create_info = LvlInitStruct<VkExportMetalObjectCreateInfoEXT>();
export_metal_object_create_info.exportObjectType = VK_EXPORT_METAL_OBJECT_TYPE_METAL_TEXTURE_BIT_EXT;
ici.format = mp_format;
ici.tiling = VK_IMAGE_TILING_OPTIMAL;
ici.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
ici.pNext = &export_metal_object_create_info;
VkImageObj mp_image_obj(m_device);
mp_image_obj.init(&ici);
metal_texture_info.bufferView = VK_NULL_HANDLE;
metal_texture_info.imageView = VK_NULL_HANDLE;
metal_texture_info.image = mp_image_obj.handle();
metal_texture_info.plane = VK_IMAGE_ASPECT_PLANE_2_BIT;
export_metal_objects_info.pNext = &metal_texture_info;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkExportMetalObjectsInfoEXT-pNext-06800");
vkExportMetalObjectsEXT(m_device->handle(), &export_metal_objects_info);
m_errorMonitor->VerifyFound();
if (ycbcr_conversion_extension) {
PFN_vkCreateSamplerYcbcrConversionKHR vkCreateSamplerYcbcrConversionKHR =
reinterpret_cast<PFN_vkCreateSamplerYcbcrConversionKHR>(
vk::GetDeviceProcAddr(m_device->device(), "vkCreateSamplerYcbcrConversionKHR"));
PFN_vkDestroySamplerYcbcrConversionKHR vkDestroySamplerYcbcrConversionKHR =
reinterpret_cast<PFN_vkDestroySamplerYcbcrConversionKHR>(
vk::GetDeviceProcAddr(m_device->device(), "vkDestroySamplerYcbcrConversionKHR"));
VkSamplerYcbcrConversionCreateInfo ycbcr_create_info = LvlInitStruct<VkSamplerYcbcrConversionCreateInfo>();
ycbcr_create_info.format = mp_format;
ycbcr_create_info.ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY;
ycbcr_create_info.ycbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_FULL;
ycbcr_create_info.components = {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY};
ycbcr_create_info.xChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN;
ycbcr_create_info.yChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN;
ycbcr_create_info.chromaFilter = VK_FILTER_NEAREST;
ycbcr_create_info.forceExplicitReconstruction = false;
VkSamplerYcbcrConversion conversion;
err = vkCreateSamplerYcbcrConversionKHR(m_device->device(), &ycbcr_create_info, nullptr, &conversion);
ASSERT_VK_SUCCESS(err);
VkSamplerYcbcrConversionInfo ycbcr_info = LvlInitStruct<VkSamplerYcbcrConversionInfo>();
ycbcr_info.conversion = conversion;
ycbcr_info.pNext = &export_metal_object_create_info;
ivci.image = mp_image_obj.handle();
ivci.format = mp_format;
ivci.pNext = &ycbcr_info;
vk_testing::ImageView mp_image_view;
mp_image_view.init(*m_device, ivci);
metal_texture_info.image = VK_NULL_HANDLE;
metal_texture_info.imageView = mp_image_view.handle();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkExportMetalObjectsInfoEXT-pNext-06802");
vkExportMetalObjectsEXT(m_device->handle(), &export_metal_objects_info);
m_errorMonitor->VerifyFound();
vkDestroySamplerYcbcrConversionKHR(m_device->device(), conversion, nullptr);
}
}
}
#endif // VK_USE_PLATFORM_METAL_EXT
TEST_F(VkLayerTest, InvalidExtEnum) {
TEST_DESCRIPTION("Use an enum from an extension that is not enabled.");
ASSERT_NO_FATAL_FAILURE(Init());
VkSamplerCreateInfo sampler_ci = SafeSaneSamplerCreateInfo();
sampler_ci.magFilter = VK_FILTER_CUBIC_EXT;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkSamplerCreateInfo-magFilter-parameter");
vk_testing::Sampler sampler(*m_device, sampler_ci);
m_errorMonitor->VerifyFound();
}
TEST_F(VkLayerTest, EndDebugLabelWithNoBegin) {
TEST_DESCRIPTION("Call vkCmdEndDebugUtilsLabelEXT without matching vkCmdBeginDebugUtilsLabelEXT");
AddRequiredExtensions(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
ASSERT_NO_FATAL_FAILURE(InitFramework());
if (!AreRequiredExtensionsEnabled()) {
GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported";
}
ASSERT_NO_FATAL_FAILURE(InitState());
auto vkCmdBeginDebugUtilsLabelEXT = reinterpret_cast<PFN_vkCmdBeginDebugUtilsLabelEXT>(
vk::GetDeviceProcAddr(m_device->device(), "vkCmdBeginDebugUtilsLabelEXT"));
ASSERT_NE(vkCmdBeginDebugUtilsLabelEXT, nullptr);
auto vkCmdEndDebugUtilsLabelEXT =
reinterpret_cast<PFN_vkCmdEndDebugUtilsLabelEXT>(vk::GetDeviceProcAddr(m_device->device(), "vkCmdEndDebugUtilsLabelEXT"));
ASSERT_NE(vkCmdEndDebugUtilsLabelEXT, nullptr);
m_commandBuffer->begin();
// First verify there is no error in the valid case
auto label = LvlInitStruct<VkDebugUtilsLabelEXT>(nullptr, "Test");
vkCmdBeginDebugUtilsLabelEXT(*m_commandBuffer, &label);
vkCmdEndDebugUtilsLabelEXT(*m_commandBuffer);
// Now call vkCmdEndDebugUtilsLabelEXT without a corresponding begin
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdEndDebugUtilsLabelEXT-commandBuffer-01912");
vkCmdEndDebugUtilsLabelEXT(*m_commandBuffer);
m_errorMonitor->VerifyFound();
m_commandBuffer->end();
// Now test the same scenario for secondary buffers
auto cb_info =
LvlInitStruct<VkCommandBufferAllocateInfo>(nullptr, m_commandPool->handle(), VK_COMMAND_BUFFER_LEVEL_SECONDARY, 1u);
vk_testing::CommandBuffer cb(*m_device, cb_info);
cb.begin();
vkCmdBeginDebugUtilsLabelEXT(cb, &label);
vkCmdEndDebugUtilsLabelEXT(cb);
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdEndDebugUtilsLabelEXT-commandBuffer-01913");
vkCmdEndDebugUtilsLabelEXT(cb);
m_errorMonitor->VerifyFound();
cb.end();
}
TEST_F(VkLayerTest, ExtensionNotEnabled) {
TEST_DESCRIPTION("Validate that using an API from an unenabled extension returns an error");
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor));
if (!AreRequiredExtensionsEnabled()) {
GTEST_SKIP() << RequiredExtensionsNotSupported() << " not supported";
}
// Require YCbCr dependencies extensions except VK_KHR_GET_MEMORY_REQUIREMENTS_2 -- to create the needed error
std::vector<const char *> required_device_extensions = {
VK_KHR_MAINTENANCE_1_EXTENSION_NAME, VK_KHR_BIND_MEMORY_2_EXTENSION_NAME, VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME};
for (auto dev_ext : required_device_extensions) {
if (DeviceExtensionSupported(dev_ext)) {
m_device_extension_names.push_back(dev_ext);
} else {
// Need to get out of the test now so that the subsequent code doesn't try to use an extension that isn't enabled.
GTEST_SKIP() << "Did not find required device extension: " << dev_ext;
}
}
// Need to ignore this error to get to the one we're testing
m_errorMonitor->SetUnexpectedError("VUID-vkCreateDevice-ppEnabledExtensionNames-01387");
ASSERT_NO_FATAL_FAILURE(InitState());
// Find address of extension API
auto vkCreateSamplerYcbcrConversionKHR =
(PFN_vkCreateSamplerYcbcrConversionKHR)vk::GetDeviceProcAddr(m_device->handle(), "vkCreateSamplerYcbcrConversionKHR");
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "UNASSIGNED-GeneralParameterError-ExtensionNotEnabled");
VkSamplerYcbcrConversionCreateInfo ycbcr_create_info = LvlInitStruct<VkSamplerYcbcrConversionCreateInfo>();
ycbcr_create_info.format = VK_FORMAT_UNDEFINED;
ycbcr_create_info.ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY;
ycbcr_create_info.ycbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_FULL;
ycbcr_create_info.components = {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY};
ycbcr_create_info.xChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN;
ycbcr_create_info.yChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN;
ycbcr_create_info.chromaFilter = VK_FILTER_NEAREST;
ycbcr_create_info.forceExplicitReconstruction = false;
VkSamplerYcbcrConversion conversion;
vkCreateSamplerYcbcrConversionKHR(m_device->handle(), &ycbcr_create_info, nullptr, &conversion);
m_errorMonitor->VerifyFound();
}
TEST_F(VkLayerTest, DuplicateValidPNextStructures) {
TEST_DESCRIPTION("Create a pNext chain containing valid structures, but with a duplicate structure type");
SetTargetApiVersion(VK_API_VERSION_1_1);
ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor));
// VK_KHR_get_physical_device_properties2 promoted to 1.1
if (DeviceValidationVersion() < VK_API_VERSION_1_1) {
GTEST_SKIP() << "At least Vulkan version 1.1 is required";
}
ASSERT_NO_FATAL_FAILURE(InitState());
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPhysicalDeviceProperties2-sType-unique");
// in VkPhysicalDeviceProperties2 create a chain of pNext of type A -> B -> A
// Also using different instance of struct to not trip the cycle checkings
VkPhysicalDeviceProtectedMemoryProperties protected_memory_properties_0 =
LvlInitStruct<VkPhysicalDeviceProtectedMemoryProperties>();
VkPhysicalDeviceIDProperties id_properties = LvlInitStruct<VkPhysicalDeviceIDProperties>(&protected_memory_properties_0);
VkPhysicalDeviceProtectedMemoryProperties protected_memory_properties_1 =
LvlInitStruct<VkPhysicalDeviceProtectedMemoryProperties>(&id_properties);
VkPhysicalDeviceProperties2 physical_device_properties2 =
LvlInitStruct<VkPhysicalDeviceProperties2>(&protected_memory_properties_1);
vk::GetPhysicalDeviceProperties2(gpu(), &physical_device_properties2);
m_errorMonitor->VerifyFound();
}