diff options
author | Mark Lobodzinski <mark@lunarg.com> | 2016-10-19 10:27:54 -0600 |
---|---|---|
committer | Tobin Ehlis <tobine@google.com> | 2016-10-20 13:20:01 -0600 |
commit | e6e61f07e474c1c86789f120099dc15782046316 (patch) | |
tree | db93bbbb5e9dfb9fe906e50be3bb8d56809a31c9 | |
parent | e4dd74afb4dc6f9701f9bf19c23574adae816ed3 (diff) | |
download | vulkan-validation-layers-e6e61f07e474c1c86789f120099dc15782046316.tar.gz |
tests: Segregate positive LVT tests
Created new test class (VkPositiveLayerTest) for positive tests,
moved existing positive test into this class and split tests having
a mix of positive and negative tests. This should make things a bit
cleaner when adding valid usage IDs and adding test names into the
VU database. In the future the class can be extended to do error
checking automatically.
Change-Id: I33af3d80f154b55bb55ad0c0e515a773b144c701
-rw-r--r-- | tests/layer_validation_tests.cpp | 8274 |
1 files changed, 4190 insertions, 4084 deletions
diff --git a/tests/layer_validation_tests.cpp b/tests/layer_validation_tests.cpp index 67e7b63b5..b2dafbfa4 100644 --- a/tests/layer_validation_tests.cpp +++ b/tests/layer_validation_tests.cpp @@ -565,6 +565,11 @@ void VkLayerTest::GenericDrawPreparation(VkCommandBufferObj *commandBuffer, VkPi commandBuffer->BindDescriptorSet(descriptorSet); } +class VkPositiveLayerTest : public VkLayerTest { + public: + protected: +}; + class VkWsiEnabledLayerTest : public VkLayerTest { public: protected: @@ -916,11 +921,9 @@ TEST_F(VkLayerTest, InvalidStructPNext) { ASSERT_NO_FATAL_FAILURE(InitState()); m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_WARNING_BIT_EXT, "value of pCreateInfo->pNext must be NULL"); - // Set VkMemoryAllocateInfo::pNext to a non-NULL value, when pNext must be - // NULL. + // Set VkMemoryAllocateInfo::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 - // parameter_validation::validate_struct_pnext + // Expected to trigger an error with parameter_validation::validate_struct_pnext VkEvent event = VK_NULL_HANDLE; VkEventCreateInfo event_alloc_info = {}; // Zero-initialization will provide the correct sType @@ -935,86 +938,13 @@ TEST_F(VkLayerTest, InvalidStructPNext) { // 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 - // parameter_validation::validate_struct_pnext + // Expected to trigger an error with parameter_validation::validate_struct_pnext VkDeviceMemory memory = VK_NULL_HANDLE; VkMemoryAllocateInfo memory_alloc_info = {}; memory_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; memory_alloc_info.pNext = &app_info; vkAllocateMemory(device(), &memory_alloc_info, NULL, &memory); m_errorMonitor->VerifyFound(); - - // Positive test to check parameter_validation and unique_objects support - // for NV_dedicated_allocation - uint32_t extension_count = 0; - bool supports_nv_dedicated_allocation = false; - VkResult err = vkEnumerateDeviceExtensionProperties(gpu(), nullptr, &extension_count, nullptr); - ASSERT_VK_SUCCESS(err); - - if (extension_count > 0) { - std::vector<VkExtensionProperties> available_extensions(extension_count); - - err = vkEnumerateDeviceExtensionProperties(gpu(), nullptr, &extension_count, &available_extensions[0]); - ASSERT_VK_SUCCESS(err); - - for (const auto &extension_props : available_extensions) { - if (strcmp(extension_props.extensionName, VK_NV_DEDICATED_ALLOCATION_EXTENSION_NAME) == 0) { - supports_nv_dedicated_allocation = true; - } - } - } - - if (supports_nv_dedicated_allocation) { - m_errorMonitor->ExpectSuccess(); - - VkDedicatedAllocationBufferCreateInfoNV dedicated_buffer_create_info = {}; - dedicated_buffer_create_info.sType = VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV; - dedicated_buffer_create_info.pNext = nullptr; - dedicated_buffer_create_info.dedicatedAllocation = VK_TRUE; - - uint32_t queue_family_index = 0; - VkBufferCreateInfo buffer_create_info = {}; - buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - buffer_create_info.pNext = &dedicated_buffer_create_info; - buffer_create_info.size = 1024; - buffer_create_info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; - buffer_create_info.queueFamilyIndexCount = 1; - buffer_create_info.pQueueFamilyIndices = &queue_family_index; - - VkBuffer buffer; - VkResult err = vkCreateBuffer(m_device->device(), &buffer_create_info, NULL, &buffer); - ASSERT_VK_SUCCESS(err); - - VkMemoryRequirements memory_reqs; - vkGetBufferMemoryRequirements(m_device->device(), buffer, &memory_reqs); - - VkDedicatedAllocationMemoryAllocateInfoNV dedicated_memory_info = {}; - dedicated_memory_info.sType = VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV; - dedicated_memory_info.pNext = nullptr; - dedicated_memory_info.buffer = buffer; - dedicated_memory_info.image = VK_NULL_HANDLE; - - VkMemoryAllocateInfo memory_info = {}; - memory_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - memory_info.pNext = &dedicated_memory_info; - memory_info.allocationSize = memory_reqs.size; - - bool pass; - pass = m_device->phy().set_memory_type(memory_reqs.memoryTypeBits, &memory_info, 0); - ASSERT_TRUE(pass); - - VkDeviceMemory buffer_memory; - err = vkAllocateMemory(m_device->device(), &memory_info, NULL, &buffer_memory); - ASSERT_VK_SUCCESS(err); - - err = vkBindBufferMemory(m_device->device(), buffer, buffer_memory, 0); - ASSERT_VK_SUCCESS(err); - - vkDestroyBuffer(m_device->device(), buffer, NULL); - vkFreeMemory(m_device->device(), buffer_memory, NULL); - - m_errorMonitor->VerifyNotFound(); - } } TEST_F(VkLayerTest, UnrecognizedValue) { @@ -1178,482 +1108,6 @@ TEST_F(VkLayerTest, FillBufferAlignment) { EndCommandBuffer(); } -// This is a positive test. No failures are expected. -TEST_F(VkLayerTest, IgnoreUnrelatedDescriptor) { - TEST_DESCRIPTION("Ensure that the vkUpdateDescriptorSets validation code " - "is ignoring VkWriteDescriptorSet members that are not " - "related to the descriptor type specified by " - "VkWriteDescriptorSet::descriptorType. Correct " - "validation behavior will result in the test running to " - "completion without validation errors."); - - const uintptr_t invalid_ptr = 0xcdcdcdcd; - - ASSERT_NO_FATAL_FAILURE(InitState()); - - // Image Case - { - m_errorMonitor->ExpectSuccess(); - - VkImage image; - const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM; - const int32_t tex_width = 32; - const int32_t tex_height = 32; - VkImageCreateInfo image_create_info = {}; - image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - image_create_info.pNext = NULL; - image_create_info.imageType = VK_IMAGE_TYPE_2D; - image_create_info.format = tex_format; - image_create_info.extent.width = tex_width; - image_create_info.extent.height = tex_height; - image_create_info.extent.depth = 1; - image_create_info.mipLevels = 1; - image_create_info.arrayLayers = 1; - image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; - image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; - image_create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT; - image_create_info.flags = 0; - VkResult err = vkCreateImage(m_device->device(), &image_create_info, NULL, &image); - ASSERT_VK_SUCCESS(err); - - VkMemoryRequirements memory_reqs; - VkDeviceMemory image_memory; - bool pass; - VkMemoryAllocateInfo memory_info = {}; - memory_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - memory_info.pNext = NULL; - memory_info.allocationSize = 0; - memory_info.memoryTypeIndex = 0; - vkGetImageMemoryRequirements(m_device->device(), image, &memory_reqs); - memory_info.allocationSize = memory_reqs.size; - pass = m_device->phy().set_memory_type(memory_reqs.memoryTypeBits, &memory_info, 0); - ASSERT_TRUE(pass); - err = vkAllocateMemory(m_device->device(), &memory_info, NULL, &image_memory); - ASSERT_VK_SUCCESS(err); - err = vkBindImageMemory(m_device->device(), image, image_memory, 0); - ASSERT_VK_SUCCESS(err); - - VkImageViewCreateInfo image_view_create_info = {}; - image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - image_view_create_info.image = image; - image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; - image_view_create_info.format = tex_format; - image_view_create_info.subresourceRange.layerCount = 1; - image_view_create_info.subresourceRange.baseMipLevel = 0; - image_view_create_info.subresourceRange.levelCount = 1; - image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - - VkImageView view; - err = vkCreateImageView(m_device->device(), &image_view_create_info, NULL, &view); - ASSERT_VK_SUCCESS(err); - - VkDescriptorPoolSize ds_type_count = {}; - ds_type_count.type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; - ds_type_count.descriptorCount = 1; - - VkDescriptorPoolCreateInfo ds_pool_ci = {}; - ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - ds_pool_ci.pNext = NULL; - ds_pool_ci.maxSets = 1; - ds_pool_ci.poolSizeCount = 1; - ds_pool_ci.pPoolSizes = &ds_type_count; - - VkDescriptorPool ds_pool; - err = vkCreateDescriptorPool(m_device->device(), &ds_pool_ci, NULL, &ds_pool); - ASSERT_VK_SUCCESS(err); - - VkDescriptorSetLayoutBinding dsl_binding = {}; - dsl_binding.binding = 0; - dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; - dsl_binding.descriptorCount = 1; - dsl_binding.stageFlags = VK_SHADER_STAGE_ALL; - dsl_binding.pImmutableSamplers = NULL; - - VkDescriptorSetLayoutCreateInfo ds_layout_ci = {}; - ds_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - ds_layout_ci.pNext = NULL; - ds_layout_ci.bindingCount = 1; - ds_layout_ci.pBindings = &dsl_binding; - VkDescriptorSetLayout ds_layout; - err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout); - ASSERT_VK_SUCCESS(err); - - VkDescriptorSet descriptor_set; - VkDescriptorSetAllocateInfo alloc_info = {}; - alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - alloc_info.descriptorSetCount = 1; - alloc_info.descriptorPool = ds_pool; - alloc_info.pSetLayouts = &ds_layout; - err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, &descriptor_set); - ASSERT_VK_SUCCESS(err); - - VkDescriptorImageInfo image_info = {}; - image_info.imageView = view; - image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - - VkWriteDescriptorSet descriptor_write; - memset(&descriptor_write, 0, sizeof(descriptor_write)); - descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - descriptor_write.dstSet = descriptor_set; - descriptor_write.dstBinding = 0; - descriptor_write.descriptorCount = 1; - descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; - descriptor_write.pImageInfo = &image_info; - - // Set pBufferInfo and pTexelBufferView to invalid values, which should - // be - // ignored for descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE. - // This will most likely produce a crash if the parameter_validation - // layer - // does not correctly ignore pBufferInfo. - descriptor_write.pBufferInfo = reinterpret_cast<const VkDescriptorBufferInfo *>(invalid_ptr); - descriptor_write.pTexelBufferView = reinterpret_cast<const VkBufferView *>(invalid_ptr); - - vkUpdateDescriptorSets(m_device->device(), 1, &descriptor_write, 0, NULL); - - m_errorMonitor->VerifyNotFound(); - - vkDestroyDescriptorSetLayout(m_device->device(), ds_layout, NULL); - vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL); - vkDestroyImageView(m_device->device(), view, NULL); - vkDestroyImage(m_device->device(), image, NULL); - vkFreeMemory(m_device->device(), image_memory, NULL); - } - - // Buffer Case - { - m_errorMonitor->ExpectSuccess(); - - VkBuffer buffer; - uint32_t queue_family_index = 0; - VkBufferCreateInfo buffer_create_info = {}; - buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - buffer_create_info.size = 1024; - buffer_create_info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; - buffer_create_info.queueFamilyIndexCount = 1; - buffer_create_info.pQueueFamilyIndices = &queue_family_index; - - VkResult err = vkCreateBuffer(m_device->device(), &buffer_create_info, NULL, &buffer); - ASSERT_VK_SUCCESS(err); - - VkMemoryRequirements memory_reqs; - VkDeviceMemory buffer_memory; - bool pass; - VkMemoryAllocateInfo memory_info = {}; - memory_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - memory_info.pNext = NULL; - memory_info.allocationSize = 0; - memory_info.memoryTypeIndex = 0; - - vkGetBufferMemoryRequirements(m_device->device(), buffer, &memory_reqs); - memory_info.allocationSize = memory_reqs.size; - pass = m_device->phy().set_memory_type(memory_reqs.memoryTypeBits, &memory_info, 0); - ASSERT_TRUE(pass); - - err = vkAllocateMemory(m_device->device(), &memory_info, NULL, &buffer_memory); - ASSERT_VK_SUCCESS(err); - err = vkBindBufferMemory(m_device->device(), buffer, buffer_memory, 0); - ASSERT_VK_SUCCESS(err); - - VkDescriptorPoolSize ds_type_count = {}; - ds_type_count.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - ds_type_count.descriptorCount = 1; - - VkDescriptorPoolCreateInfo ds_pool_ci = {}; - ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - ds_pool_ci.pNext = NULL; - ds_pool_ci.maxSets = 1; - ds_pool_ci.poolSizeCount = 1; - ds_pool_ci.pPoolSizes = &ds_type_count; - - VkDescriptorPool ds_pool; - err = vkCreateDescriptorPool(m_device->device(), &ds_pool_ci, NULL, &ds_pool); - ASSERT_VK_SUCCESS(err); - - VkDescriptorSetLayoutBinding dsl_binding = {}; - dsl_binding.binding = 0; - dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - dsl_binding.descriptorCount = 1; - dsl_binding.stageFlags = VK_SHADER_STAGE_ALL; - dsl_binding.pImmutableSamplers = NULL; - - VkDescriptorSetLayoutCreateInfo ds_layout_ci = {}; - ds_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - ds_layout_ci.pNext = NULL; - ds_layout_ci.bindingCount = 1; - ds_layout_ci.pBindings = &dsl_binding; - VkDescriptorSetLayout ds_layout; - err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout); - ASSERT_VK_SUCCESS(err); - - VkDescriptorSet descriptor_set; - VkDescriptorSetAllocateInfo alloc_info = {}; - alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - alloc_info.descriptorSetCount = 1; - alloc_info.descriptorPool = ds_pool; - alloc_info.pSetLayouts = &ds_layout; - err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, &descriptor_set); - ASSERT_VK_SUCCESS(err); - - VkDescriptorBufferInfo buffer_info = {}; - buffer_info.buffer = buffer; - buffer_info.offset = 0; - buffer_info.range = 1024; - - VkWriteDescriptorSet descriptor_write; - memset(&descriptor_write, 0, sizeof(descriptor_write)); - descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - descriptor_write.dstSet = descriptor_set; - descriptor_write.dstBinding = 0; - descriptor_write.descriptorCount = 1; - descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - descriptor_write.pBufferInfo = &buffer_info; - - // Set pImageInfo and pTexelBufferView to invalid values, which should - // be - // ignored for descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER. - // This will most likely produce a crash if the parameter_validation - // layer - // does not correctly ignore pImageInfo. - descriptor_write.pImageInfo = reinterpret_cast<const VkDescriptorImageInfo *>(invalid_ptr); - descriptor_write.pTexelBufferView = reinterpret_cast<const VkBufferView *>(invalid_ptr); - - vkUpdateDescriptorSets(m_device->device(), 1, &descriptor_write, 0, NULL); - - m_errorMonitor->VerifyNotFound(); - - vkFreeDescriptorSets(m_device->device(), ds_pool, 1, &descriptor_set); - vkDestroyDescriptorSetLayout(m_device->device(), ds_layout, NULL); - vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL); - vkDestroyBuffer(m_device->device(), buffer, NULL); - vkFreeMemory(m_device->device(), buffer_memory, NULL); - } - - // Texel Buffer Case - { - m_errorMonitor->ExpectSuccess(); - - VkBuffer buffer; - uint32_t queue_family_index = 0; - VkBufferCreateInfo buffer_create_info = {}; - buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - 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; - - VkResult err = vkCreateBuffer(m_device->device(), &buffer_create_info, NULL, &buffer); - ASSERT_VK_SUCCESS(err); - - VkMemoryRequirements memory_reqs; - VkDeviceMemory buffer_memory; - bool pass; - VkMemoryAllocateInfo memory_info = {}; - memory_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - memory_info.pNext = NULL; - memory_info.allocationSize = 0; - memory_info.memoryTypeIndex = 0; - - vkGetBufferMemoryRequirements(m_device->device(), buffer, &memory_reqs); - memory_info.allocationSize = memory_reqs.size; - pass = m_device->phy().set_memory_type(memory_reqs.memoryTypeBits, &memory_info, 0); - ASSERT_TRUE(pass); - - err = vkAllocateMemory(m_device->device(), &memory_info, NULL, &buffer_memory); - ASSERT_VK_SUCCESS(err); - err = vkBindBufferMemory(m_device->device(), buffer, buffer_memory, 0); - ASSERT_VK_SUCCESS(err); - - VkBufferViewCreateInfo buff_view_ci = {}; - buff_view_ci.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO; - buff_view_ci.buffer = buffer; - buff_view_ci.format = VK_FORMAT_R8_UNORM; - buff_view_ci.range = VK_WHOLE_SIZE; - VkBufferView buffer_view; - err = vkCreateBufferView(m_device->device(), &buff_view_ci, NULL, &buffer_view); - - VkDescriptorPoolSize ds_type_count = {}; - ds_type_count.type = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; - ds_type_count.descriptorCount = 1; - - VkDescriptorPoolCreateInfo ds_pool_ci = {}; - ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - ds_pool_ci.pNext = NULL; - ds_pool_ci.maxSets = 1; - ds_pool_ci.poolSizeCount = 1; - ds_pool_ci.pPoolSizes = &ds_type_count; - - VkDescriptorPool ds_pool; - err = vkCreateDescriptorPool(m_device->device(), &ds_pool_ci, NULL, &ds_pool); - ASSERT_VK_SUCCESS(err); - - VkDescriptorSetLayoutBinding dsl_binding = {}; - dsl_binding.binding = 0; - dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; - dsl_binding.descriptorCount = 1; - dsl_binding.stageFlags = VK_SHADER_STAGE_ALL; - dsl_binding.pImmutableSamplers = NULL; - - VkDescriptorSetLayoutCreateInfo ds_layout_ci = {}; - ds_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - ds_layout_ci.pNext = NULL; - ds_layout_ci.bindingCount = 1; - ds_layout_ci.pBindings = &dsl_binding; - VkDescriptorSetLayout ds_layout; - err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout); - ASSERT_VK_SUCCESS(err); - - VkDescriptorSet descriptor_set; - VkDescriptorSetAllocateInfo alloc_info = {}; - alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - alloc_info.descriptorSetCount = 1; - alloc_info.descriptorPool = ds_pool; - alloc_info.pSetLayouts = &ds_layout; - err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, &descriptor_set); - ASSERT_VK_SUCCESS(err); - - VkWriteDescriptorSet descriptor_write; - memset(&descriptor_write, 0, sizeof(descriptor_write)); - descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - descriptor_write.dstSet = descriptor_set; - descriptor_write.dstBinding = 0; - descriptor_write.descriptorCount = 1; - descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; - descriptor_write.pTexelBufferView = &buffer_view; - - // Set pImageInfo and pBufferInfo to invalid values, which should be - // ignored for descriptorType == - // VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER. - // This will most likely produce a crash if the parameter_validation - // layer - // does not correctly ignore pImageInfo and pBufferInfo. - descriptor_write.pImageInfo = reinterpret_cast<const VkDescriptorImageInfo *>(invalid_ptr); - descriptor_write.pBufferInfo = reinterpret_cast<const VkDescriptorBufferInfo *>(invalid_ptr); - - vkUpdateDescriptorSets(m_device->device(), 1, &descriptor_write, 0, NULL); - - m_errorMonitor->VerifyNotFound(); - - vkFreeDescriptorSets(m_device->device(), ds_pool, 1, &descriptor_set); - vkDestroyDescriptorSetLayout(m_device->device(), ds_layout, NULL); - vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL); - vkDestroyBufferView(m_device->device(), buffer_view, NULL); - vkDestroyBuffer(m_device->device(), buffer, NULL); - vkFreeMemory(m_device->device(), buffer_memory, NULL); - } -} - -// This is a positive test. No failures are expected. -TEST_F(VkLayerTest, EmptyDescriptorUpdateTest) { - TEST_DESCRIPTION("Update last descriptor in a set that includes an empty binding"); - VkResult err; - - ASSERT_NO_FATAL_FAILURE(InitState()); - m_errorMonitor->ExpectSuccess(); - VkDescriptorPoolSize ds_type_count = {}; - ds_type_count.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - ds_type_count.descriptorCount = 2; - - VkDescriptorPoolCreateInfo ds_pool_ci = {}; - ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - ds_pool_ci.pNext = NULL; - ds_pool_ci.maxSets = 1; - ds_pool_ci.poolSizeCount = 1; - ds_pool_ci.pPoolSizes = &ds_type_count; - - VkDescriptorPool ds_pool; - err = vkCreateDescriptorPool(m_device->device(), &ds_pool_ci, NULL, &ds_pool); - ASSERT_VK_SUCCESS(err); - - // Create layout with two uniform buffer descriptors w/ empty binding between them - static const uint32_t NUM_BINDINGS = 3; - VkDescriptorSetLayoutBinding dsl_binding[NUM_BINDINGS] = {}; - dsl_binding[0].binding = 0; - dsl_binding[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - dsl_binding[0].descriptorCount = 1; - dsl_binding[0].stageFlags = VK_SHADER_STAGE_ALL; - dsl_binding[0].pImmutableSamplers = NULL; - dsl_binding[1].binding = 1; - dsl_binding[1].descriptorCount = 0; // empty binding - dsl_binding[2].binding = 2; - dsl_binding[2].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - dsl_binding[2].descriptorCount = 1; - dsl_binding[2].stageFlags = VK_SHADER_STAGE_ALL; - dsl_binding[2].pImmutableSamplers = NULL; - - VkDescriptorSetLayoutCreateInfo ds_layout_ci = {}; - ds_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - ds_layout_ci.pNext = NULL; - ds_layout_ci.bindingCount = NUM_BINDINGS; - ds_layout_ci.pBindings = dsl_binding; - VkDescriptorSetLayout ds_layout; - err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout); - ASSERT_VK_SUCCESS(err); - - VkDescriptorSet descriptor_set = {}; - VkDescriptorSetAllocateInfo alloc_info = {}; - alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - alloc_info.descriptorSetCount = 1; - alloc_info.descriptorPool = ds_pool; - alloc_info.pSetLayouts = &ds_layout; - err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, &descriptor_set); - ASSERT_VK_SUCCESS(err); - - // Create a buffer to be used for update - VkBufferCreateInfo buff_ci = {}; - buff_ci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - buff_ci.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; - buff_ci.size = 256; - buff_ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - VkBuffer buffer; - err = vkCreateBuffer(m_device->device(), &buff_ci, NULL, &buffer); - ASSERT_VK_SUCCESS(err); - // Have to bind memory to buffer before descriptor update - VkMemoryAllocateInfo mem_alloc = {}; - mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - mem_alloc.pNext = NULL; - mem_alloc.allocationSize = 512; // one allocation for both buffers - mem_alloc.memoryTypeIndex = 0; - - VkMemoryRequirements mem_reqs; - vkGetBufferMemoryRequirements(m_device->device(), buffer, &mem_reqs); - bool pass = m_device->phy().set_memory_type(mem_reqs.memoryTypeBits, &mem_alloc, 0); - if (!pass) { - vkDestroyBuffer(m_device->device(), buffer, NULL); - return; - } - - VkDeviceMemory mem; - err = vkAllocateMemory(m_device->device(), &mem_alloc, NULL, &mem); - ASSERT_VK_SUCCESS(err); - err = vkBindBufferMemory(m_device->device(), buffer, mem, 0); - ASSERT_VK_SUCCESS(err); - - // Only update the descriptor at binding 2 - VkDescriptorBufferInfo buff_info = {}; - buff_info.buffer = buffer; - buff_info.offset = 0; - buff_info.range = VK_WHOLE_SIZE; - VkWriteDescriptorSet descriptor_write = {}; - descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - descriptor_write.dstBinding = 2; - descriptor_write.descriptorCount = 1; - descriptor_write.pTexelBufferView = nullptr; - descriptor_write.pBufferInfo = &buff_info; - descriptor_write.pImageInfo = nullptr; - descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - descriptor_write.dstSet = descriptor_set; - - vkUpdateDescriptorSets(m_device->device(), 1, &descriptor_write, 0, NULL); - - m_errorMonitor->VerifyNotFound(); - // Cleanup - vkFreeMemory(m_device->device(), mem, NULL); - vkDestroyDescriptorSetLayout(m_device->device(), ds_layout, NULL); - vkDestroyBuffer(m_device->device(), buffer, NULL); - vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL); -} - TEST_F(VkLayerTest, PSOPolygonModeInvalid) { VkResult err; @@ -1720,20 +1174,6 @@ TEST_F(VkLayerTest, PSOPolygonModeInvalid) { } m_errorMonitor->VerifyFound(); - // Try again with polygonMode=FILL. No error is expected - m_errorMonitor->ExpectSuccess(); - { - VkPipelineObj pipe(&test_device); - pipe.AddShader(&vs); - pipe.AddShader(&fs); - pipe.AddColorAttachment(); - // Set polygonMode to a good value - rs_ci.polygonMode = VK_POLYGON_MODE_FILL; - pipe.SetRasterization(&rs_ci); - pipe.CreateVKPipeline(pipeline_layout, render_pass.handle()); - } - m_errorMonitor->VerifyNotFound(); - vkDestroyPipelineLayout(test_device.device(), pipeline_layout, NULL); } @@ -1839,124 +1279,6 @@ TEST_F(VkLayerTest, CallBeginCommandBufferBeforeCompletion) } #endif -// This is a positive test. No failures are expected. -TEST_F(VkLayerTest, TestAliasedMemoryTracking) { - VkResult err; - bool pass; - - TEST_DESCRIPTION("Create a buffer, allocate memory, bind memory, destroy " - "the buffer, create an image, and bind the same memory to " - "it"); - - m_errorMonitor->ExpectSuccess(); - - ASSERT_NO_FATAL_FAILURE(InitState()); - - VkBuffer buffer; - VkImage image; - VkDeviceMemory mem; - VkMemoryRequirements mem_reqs; - - VkBufferCreateInfo buf_info = {}; - buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - buf_info.pNext = NULL; - buf_info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; - buf_info.size = 256; - buf_info.queueFamilyIndexCount = 0; - buf_info.pQueueFamilyIndices = NULL; - buf_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - buf_info.flags = 0; - err = vkCreateBuffer(m_device->device(), &buf_info, NULL, &buffer); - ASSERT_VK_SUCCESS(err); - - vkGetBufferMemoryRequirements(m_device->device(), buffer, &mem_reqs); - - VkMemoryAllocateInfo alloc_info = {}; - alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - alloc_info.pNext = NULL; - alloc_info.memoryTypeIndex = 0; - - // Ensure memory is big enough for both bindings - alloc_info.allocationSize = 0x10000; - - pass = m_device->phy().set_memory_type(mem_reqs.memoryTypeBits, &alloc_info, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); - if (!pass) { - vkDestroyBuffer(m_device->device(), buffer, NULL); - return; - } - - err = vkAllocateMemory(m_device->device(), &alloc_info, NULL, &mem); - ASSERT_VK_SUCCESS(err); - - uint8_t *pData; - err = vkMapMemory(m_device->device(), mem, 0, mem_reqs.size, 0, (void **)&pData); - ASSERT_VK_SUCCESS(err); - - memset(pData, 0xCADECADE, static_cast<size_t>(mem_reqs.size)); - - vkUnmapMemory(m_device->device(), mem); - - err = vkBindBufferMemory(m_device->device(), buffer, mem, 0); - ASSERT_VK_SUCCESS(err); - - // NOW, destroy the buffer. Obviously, the resource no longer occupies this - // memory. In fact, it was never used by the GPU. - // Just be be sure, wait for idle. - vkDestroyBuffer(m_device->device(), buffer, NULL); - vkDeviceWaitIdle(m_device->device()); - - VkImageCreateInfo image_create_info = {}; - image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - image_create_info.pNext = NULL; - image_create_info.imageType = VK_IMAGE_TYPE_2D; - image_create_info.format = VK_FORMAT_R8G8B8A8_UNORM; - image_create_info.extent.width = 64; - image_create_info.extent.height = 64; - image_create_info.extent.depth = 1; - image_create_info.mipLevels = 1; - image_create_info.arrayLayers = 1; - image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; - image_create_info.tiling = VK_IMAGE_TILING_LINEAR; - image_create_info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; - image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT; - image_create_info.queueFamilyIndexCount = 0; - image_create_info.pQueueFamilyIndices = NULL; - image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - image_create_info.flags = 0; - - VkMemoryAllocateInfo mem_alloc = {}; - mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - mem_alloc.pNext = NULL; - mem_alloc.allocationSize = 0; - mem_alloc.memoryTypeIndex = 0; - - /* Create a mappable image. It will be the texture if linear images are ok - * to be textures or it will be the staging image if they are not. - */ - err = vkCreateImage(m_device->device(), &image_create_info, NULL, &image); - ASSERT_VK_SUCCESS(err); - - vkGetImageMemoryRequirements(m_device->device(), image, &mem_reqs); - - mem_alloc.allocationSize = mem_reqs.size; - - pass = m_device->phy().set_memory_type(mem_reqs.memoryTypeBits, &mem_alloc, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); - if (!pass) { - vkDestroyImage(m_device->device(), image, NULL); - return; - } - - // VALIDATION FAILURE: - err = vkBindImageMemory(m_device->device(), image, mem, 0); - ASSERT_VK_SUCCESS(err); - - m_errorMonitor->VerifyNotFound(); - - vkFreeMemory(m_device->device(), mem, NULL); - vkDestroyBuffer(m_device->device(), buffer, NULL); - vkDestroyImage(m_device->device(), image, NULL); -} - TEST_F(VkLayerTest, InvalidMemoryAliasing) { TEST_DESCRIPTION("Create a buffer and image, allocate memory, and bind the " "buffer and image to memory such that they will alias."); @@ -2156,116 +1478,6 @@ TEST_F(VkLayerTest, InvalidMemoryMapping) { vkFreeMemory(m_device->device(), mem, NULL); } -TEST_F(VkLayerTest, NonCoherentMemoryMapping) { - - TEST_DESCRIPTION("Ensure that validations handling of non-coherent memory " - "mapping while using VK_WHOLE_SIZE does not cause access " - "violations"); - VkResult err; - uint8_t *pData; - ASSERT_NO_FATAL_FAILURE(InitState()); - - VkDeviceMemory mem; - VkMemoryRequirements mem_reqs; - mem_reqs.memoryTypeBits = 0xFFFFFFFF; - VkMemoryAllocateInfo alloc_info = {}; - alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - alloc_info.pNext = NULL; - alloc_info.memoryTypeIndex = 0; - - static const VkDeviceSize allocation_size = 0x1000; - alloc_info.allocationSize = allocation_size; - - // Find a memory configurations WITHOUT a COHERENT bit, otherwise exit - bool pass = m_device->phy().set_memory_type(mem_reqs.memoryTypeBits, &alloc_info, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - if (!pass) { - pass = m_device->phy().set_memory_type(mem_reqs.memoryTypeBits, &alloc_info, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - if (!pass) { - pass = m_device->phy().set_memory_type(mem_reqs.memoryTypeBits, &alloc_info, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | - VK_MEMORY_PROPERTY_HOST_CACHED_BIT, - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - if (!pass) { - return; - } - } - } - - err = vkAllocateMemory(m_device->device(), &alloc_info, NULL, &mem); - ASSERT_VK_SUCCESS(err); - - // Map/Flush/Invalidate using WHOLE_SIZE and zero offsets and entire - // mapped range - m_errorMonitor->ExpectSuccess(); - err = vkMapMemory(m_device->device(), mem, 0, VK_WHOLE_SIZE, 0, (void **)&pData); - ASSERT_VK_SUCCESS(err); - VkMappedMemoryRange mmr = {}; - mmr.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; - mmr.memory = mem; - mmr.offset = 0; - mmr.size = VK_WHOLE_SIZE; - err = vkFlushMappedMemoryRanges(m_device->device(), 1, &mmr); - ASSERT_VK_SUCCESS(err); - err = vkInvalidateMappedMemoryRanges(m_device->device(), 1, &mmr); - ASSERT_VK_SUCCESS(err); - m_errorMonitor->VerifyNotFound(); - vkUnmapMemory(m_device->device(), mem); - - // Map/Flush/Invalidate using WHOLE_SIZE and a prime offset and entire - // mapped range - m_errorMonitor->ExpectSuccess(); - err = vkMapMemory(m_device->device(), mem, 13, VK_WHOLE_SIZE, 0, (void **)&pData); - ASSERT_VK_SUCCESS(err); - mmr.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; - mmr.memory = mem; - mmr.offset = 13; - mmr.size = VK_WHOLE_SIZE; - err = vkFlushMappedMemoryRanges(m_device->device(), 1, &mmr); - ASSERT_VK_SUCCESS(err); - err = vkInvalidateMappedMemoryRanges(m_device->device(), 1, &mmr); - ASSERT_VK_SUCCESS(err); - m_errorMonitor->VerifyNotFound(); - vkUnmapMemory(m_device->device(), mem); - - // Map with prime offset and size - // Flush/Invalidate subrange of mapped area with prime offset and size - m_errorMonitor->ExpectSuccess(); - err = vkMapMemory(m_device->device(), mem, allocation_size - 137, 109, 0, (void **)&pData); - ASSERT_VK_SUCCESS(err); - mmr.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; - mmr.memory = mem; - mmr.offset = allocation_size - 107; - mmr.size = 61; - err = vkFlushMappedMemoryRanges(m_device->device(), 1, &mmr); - ASSERT_VK_SUCCESS(err); - err = vkInvalidateMappedMemoryRanges(m_device->device(), 1, &mmr); - ASSERT_VK_SUCCESS(err); - m_errorMonitor->VerifyNotFound(); - vkUnmapMemory(m_device->device(), mem); - - // Map without offset and flush WHOLE_SIZE with two separate offsets - m_errorMonitor->ExpectSuccess(); - err = vkMapMemory(m_device->device(), mem, 0, VK_WHOLE_SIZE, 0, (void **)&pData); - ASSERT_VK_SUCCESS(err); - mmr.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; - mmr.memory = mem; - mmr.offset = allocation_size - 100; - mmr.size = VK_WHOLE_SIZE; - err = vkFlushMappedMemoryRanges(m_device->device(), 1, &mmr); - ASSERT_VK_SUCCESS(err); - mmr.offset = allocation_size - 200; - mmr.size = VK_WHOLE_SIZE; - err = vkFlushMappedMemoryRanges(m_device->device(), 1, &mmr); - ASSERT_VK_SUCCESS(err); - m_errorMonitor->VerifyNotFound(); - vkUnmapMemory(m_device->device(), mem); - - vkFreeMemory(m_device->device(), mem, NULL); -} - TEST_F(VkLayerTest, EnableWsiBeforeUse) { VkResult err; bool pass; @@ -2494,341 +1706,6 @@ TEST_F(VkLayerTest, EnableWsiBeforeUse) { m_errorMonitor->VerifyFound(); } -TEST_F(VkWsiEnabledLayerTest, TestEnabledWsi) { - -#if defined(VK_USE_PLATFORM_XCB_KHR) - VkSurfaceKHR surface = VK_NULL_HANDLE; - - VkResult err; - bool pass; - VkSwapchainKHR swapchain = VK_NULL_HANDLE; - VkSwapchainCreateInfoKHR swapchain_create_info = {}; - // uint32_t swapchain_image_count = 0; - // VkImage swapchain_images[1] = {VK_NULL_HANDLE}; - // uint32_t image_index = 0; - // VkPresentInfoKHR present_info = {}; - - ASSERT_NO_FATAL_FAILURE(InitState()); - - // Use the create function from one of the VK_KHR_*_surface extension in - // order to create a surface, testing all known errors in the process, - // before successfully creating a surface: - // First, try to create a surface without a VkXcbSurfaceCreateInfoKHR: - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "required parameter pCreateInfo specified as NULL"); - err = vkCreateXcbSurfaceKHR(instance(), NULL, NULL, &surface); - pass = (err != VK_SUCCESS); - ASSERT_TRUE(pass); - m_errorMonitor->VerifyFound(); - - // Next, try to create a surface with the wrong - // VkXcbSurfaceCreateInfoKHR::sType: - VkXcbSurfaceCreateInfoKHR xcb_create_info = {}; - xcb_create_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "parameter pCreateInfo->sType must be"); - err = vkCreateXcbSurfaceKHR(instance(), &xcb_create_info, NULL, &surface); - pass = (err != VK_SUCCESS); - ASSERT_TRUE(pass); - m_errorMonitor->VerifyFound(); - - // Create a native window, and then correctly create a surface: - xcb_connection_t *connection; - xcb_screen_t *screen; - xcb_window_t xcb_window; - xcb_intern_atom_reply_t *atom_wm_delete_window; - - const xcb_setup_t *setup; - xcb_screen_iterator_t iter; - int scr; - uint32_t value_mask, value_list[32]; - int width = 1; - int height = 1; - - connection = xcb_connect(NULL, &scr); - ASSERT_TRUE(connection != NULL); - setup = xcb_get_setup(connection); - iter = xcb_setup_roots_iterator(setup); - while (scr-- > 0) - xcb_screen_next(&iter); - screen = iter.data; - - xcb_window = xcb_generate_id(connection); - - value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; - value_list[0] = screen->black_pixel; - value_list[1] = XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY; - - xcb_create_window(connection, XCB_COPY_FROM_PARENT, xcb_window, screen->root, 0, 0, width, height, 0, - XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, value_mask, value_list); - - /* Magic code that will send notification when window is destroyed */ - xcb_intern_atom_cookie_t cookie = xcb_intern_atom(connection, 1, 12, "WM_PROTOCOLS"); - xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(connection, cookie, 0); - - xcb_intern_atom_cookie_t cookie2 = xcb_intern_atom(connection, 0, 16, "WM_DELETE_WINDOW"); - atom_wm_delete_window = xcb_intern_atom_reply(connection, cookie2, 0); - xcb_change_property(connection, XCB_PROP_MODE_REPLACE, xcb_window, (*reply).atom, 4, 32, 1, &(*atom_wm_delete_window).atom); - free(reply); - - xcb_map_window(connection, xcb_window); - - // Force the x/y coordinates to 100,100 results are identical in consecutive - // runs - const uint32_t coords[] = {100, 100}; - xcb_configure_window(connection, xcb_window, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, coords); - - // Finally, try to correctly create a surface: - xcb_create_info.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; - xcb_create_info.pNext = NULL; - xcb_create_info.flags = 0; - xcb_create_info.connection = connection; - xcb_create_info.window = xcb_window; - err = vkCreateXcbSurfaceKHR(instance(), &xcb_create_info, NULL, &surface); - pass = (err == VK_SUCCESS); - ASSERT_TRUE(pass); - - // Check if surface supports presentation: - - // 1st, do so without having queried the queue families: - VkBool32 supported = false; - // TODO: Get the following error to come out: - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, - "called before calling the vkGetPhysicalDeviceQueueFamilyProperties " - "function"); - err = vkGetPhysicalDeviceSurfaceSupportKHR(gpu(), 0, surface, &supported); - pass = (err != VK_SUCCESS); - // ASSERT_TRUE(pass); - // m_errorMonitor->VerifyFound(); - - // Next, query a queue family index that's too large: - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "called with a queueFamilyIndex that is too large"); - err = vkGetPhysicalDeviceSurfaceSupportKHR(gpu(), 100000, surface, &supported); - pass = (err != VK_SUCCESS); - ASSERT_TRUE(pass); - m_errorMonitor->VerifyFound(); - - // Finally, do so correctly: - // FIXME: THIS ISN'T CORRECT--MUST QUERY UNTIL WE FIND A QUEUE FAMILY THAT'S - // SUPPORTED - err = vkGetPhysicalDeviceSurfaceSupportKHR(gpu(), 0, surface, &supported); - pass = (err == VK_SUCCESS); - ASSERT_TRUE(pass); - - // Before proceeding, try to create a swapchain without having called - // vkGetPhysicalDeviceSurfaceCapabilitiesKHR(): - swapchain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; - swapchain_create_info.pNext = NULL; - swapchain_create_info.flags = 0; - swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - swapchain_create_info.surface = surface; - swapchain_create_info.imageArrayLayers = 1; - swapchain_create_info.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; - swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, - "called before calling vkGetPhysicalDeviceSurfaceCapabilitiesKHR()."); - err = vkCreateSwapchainKHR(m_device->device(), &swapchain_create_info, NULL, &swapchain); - pass = (err != VK_SUCCESS); - ASSERT_TRUE(pass); - m_errorMonitor->VerifyFound(); - - // Get the surface capabilities: - VkSurfaceCapabilitiesKHR surface_capabilities; - - // Do so correctly (only error logged by this entrypoint is if the - // extension isn't enabled): - err = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(gpu(), surface, &surface_capabilities); - pass = (err == VK_SUCCESS); - ASSERT_TRUE(pass); - - // Get the surface formats: - uint32_t surface_format_count; - - // First, try without a pointer to surface_format_count: - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "required parameter pSurfaceFormatCount " - "specified as NULL"); - vkGetPhysicalDeviceSurfaceFormatsKHR(gpu(), surface, NULL, NULL); - pass = (err == VK_SUCCESS); - ASSERT_TRUE(pass); - m_errorMonitor->VerifyFound(); - - // Next, call with a non-NULL pSurfaceFormats, even though we haven't - // correctly done a 1st try (to get the count): - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_WARNING_BIT_EXT, "but no prior positive value has been seen for"); - surface_format_count = 0; - vkGetPhysicalDeviceSurfaceFormatsKHR(gpu(), surface, &surface_format_count, (VkSurfaceFormatKHR *)&surface_format_count); - pass = (err == VK_SUCCESS); - ASSERT_TRUE(pass); - m_errorMonitor->VerifyFound(); - - // Next, correctly do a 1st try (with a NULL pointer to surface_formats): - vkGetPhysicalDeviceSurfaceFormatsKHR(gpu(), surface, &surface_format_count, NULL); - pass = (err == VK_SUCCESS); - ASSERT_TRUE(pass); - - // Allocate memory for the correct number of VkSurfaceFormatKHR's: - VkSurfaceFormatKHR *surface_formats = (VkSurfaceFormatKHR *)malloc(surface_format_count * sizeof(VkSurfaceFormatKHR)); - - // Next, do a 2nd try with surface_format_count being set too high: - surface_format_count += 5; - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "that is greater than the value"); - vkGetPhysicalDeviceSurfaceFormatsKHR(gpu(), surface, &surface_format_count, surface_formats); - pass = (err == VK_SUCCESS); - ASSERT_TRUE(pass); - m_errorMonitor->VerifyFound(); - - // Finally, do a correct 1st and 2nd try: - vkGetPhysicalDeviceSurfaceFormatsKHR(gpu(), surface, &surface_format_count, NULL); - pass = (err == VK_SUCCESS); - ASSERT_TRUE(pass); - vkGetPhysicalDeviceSurfaceFormatsKHR(gpu(), surface, &surface_format_count, surface_formats); - pass = (err == VK_SUCCESS); - ASSERT_TRUE(pass); - - // Get the surface present modes: - uint32_t surface_present_mode_count; - - // First, try without a pointer to surface_format_count: - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "required parameter pPresentModeCount " - "specified as NULL"); - - vkGetPhysicalDeviceSurfacePresentModesKHR(gpu(), surface, NULL, NULL); - pass = (err == VK_SUCCESS); - ASSERT_TRUE(pass); - m_errorMonitor->VerifyFound(); - - // Next, call with a non-NULL VkPresentModeKHR, even though we haven't - // correctly done a 1st try (to get the count): - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_WARNING_BIT_EXT, "but no prior positive value has been seen for"); - surface_present_mode_count = 0; - vkGetPhysicalDeviceSurfacePresentModesKHR(gpu(), surface, &surface_present_mode_count, - (VkPresentModeKHR *)&surface_present_mode_count); - pass = (err == VK_SUCCESS); - ASSERT_TRUE(pass); - m_errorMonitor->VerifyFound(); - - // Next, correctly do a 1st try (with a NULL pointer to surface_formats): - vkGetPhysicalDeviceSurfacePresentModesKHR(gpu(), surface, &surface_present_mode_count, NULL); - pass = (err == VK_SUCCESS); - ASSERT_TRUE(pass); - - // Allocate memory for the correct number of VkSurfaceFormatKHR's: - VkPresentModeKHR *surface_present_modes = (VkPresentModeKHR *)malloc(surface_present_mode_count * sizeof(VkPresentModeKHR)); - - // Next, do a 2nd try with surface_format_count being set too high: - surface_present_mode_count += 5; - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "that is greater than the value"); - vkGetPhysicalDeviceSurfacePresentModesKHR(gpu(), surface, &surface_present_mode_count, surface_present_modes); - pass = (err == VK_SUCCESS); - ASSERT_TRUE(pass); - m_errorMonitor->VerifyFound(); - - // Finally, do a correct 1st and 2nd try: - vkGetPhysicalDeviceSurfacePresentModesKHR(gpu(), surface, &surface_present_mode_count, NULL); - pass = (err == VK_SUCCESS); - ASSERT_TRUE(pass); - vkGetPhysicalDeviceSurfacePresentModesKHR(gpu(), surface, &surface_present_mode_count, surface_present_modes); - pass = (err == VK_SUCCESS); - ASSERT_TRUE(pass); - - // Create a swapchain: - - // First, try without a pointer to swapchain_create_info: - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "required parameter pCreateInfo " - "specified as NULL"); - - err = vkCreateSwapchainKHR(m_device->device(), NULL, NULL, &swapchain); - pass = (err != VK_SUCCESS); - ASSERT_TRUE(pass); - m_errorMonitor->VerifyFound(); - - // Next, call with a non-NULL swapchain_create_info, that has the wrong - // sType: - swapchain_create_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "parameter pCreateInfo->sType must be"); - - err = vkCreateSwapchainKHR(m_device->device(), &swapchain_create_info, NULL, &swapchain); - pass = (err != VK_SUCCESS); - ASSERT_TRUE(pass); - m_errorMonitor->VerifyFound(); - - // Next, call with a NULL swapchain pointer: - swapchain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; - swapchain_create_info.pNext = NULL; - swapchain_create_info.flags = 0; - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "required parameter pSwapchain " - "specified as NULL"); - - err = vkCreateSwapchainKHR(m_device->device(), &swapchain_create_info, NULL, NULL); - pass = (err != VK_SUCCESS); - ASSERT_TRUE(pass); - m_errorMonitor->VerifyFound(); - - // TODO: Enhance swapchain layer so that - // swapchain_create_info.queueFamilyIndexCount is checked against something? - - // Next, call with a queue family index that's too large: - uint32_t queueFamilyIndex[2] = {100000, 0}; - swapchain_create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT; - swapchain_create_info.queueFamilyIndexCount = 2; - swapchain_create_info.pQueueFamilyIndices = queueFamilyIndex; - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "called with a queueFamilyIndex that is too large"); - err = vkCreateSwapchainKHR(m_device->device(), &swapchain_create_info, NULL, &swapchain); - pass = (err != VK_SUCCESS); - ASSERT_TRUE(pass); - m_errorMonitor->VerifyFound(); - - // Next, call a queueFamilyIndexCount that's too small for CONCURRENT: - swapchain_create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT; - swapchain_create_info.queueFamilyIndexCount = 1; - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, - "but with a bad value(s) for pCreateInfo->queueFamilyIndexCount or " - "pCreateInfo->pQueueFamilyIndices)."); - err = vkCreateSwapchainKHR(m_device->device(), &swapchain_create_info, NULL, &swapchain); - pass = (err != VK_SUCCESS); - ASSERT_TRUE(pass); - m_errorMonitor->VerifyFound(); - - // Next, call with an invalid imageSharingMode: - swapchain_create_info.imageSharingMode = VK_SHARING_MODE_MAX_ENUM; - swapchain_create_info.queueFamilyIndexCount = 1; - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, - "called with a non-supported pCreateInfo->imageSharingMode (i.e."); - err = vkCreateSwapchainKHR(m_device->device(), &swapchain_create_info, NULL, &swapchain); - pass = (err != VK_SUCCESS); - ASSERT_TRUE(pass); - m_errorMonitor->VerifyFound(); - // Fix for the future: - // FIXME: THIS ISN'T CORRECT--MUST QUERY UNTIL WE FIND A QUEUE FAMILY THAT'S - // SUPPORTED - swapchain_create_info.queueFamilyIndexCount = 0; - queueFamilyIndex[0] = 0; - swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; - - // TODO: CONTINUE TESTING VALIDATION OF vkCreateSwapchainKHR() ... - // Get the images from a swapchain: - // Acquire an image from a swapchain: - // Present an image to a swapchain: - // Destroy the swapchain: - - // TODOs: - // - // - Try destroying the device without first destroying the swapchain - // - // - Try destroying the device without first destroying the surface - // - // - Try destroying the surface without first destroying the swapchain - - // Destroy the surface: - vkDestroySurfaceKHR(instance(), surface, NULL); - - // Tear down the window: - xcb_destroy_window(connection, xcb_window); - xcb_disconnect(connection); - -#else // VK_USE_PLATFORM_XCB_KHR - return; -#endif // VK_USE_PLATFORM_XCB_KHR -} - TEST_F(VkLayerTest, MapMemWithoutHostVisibleBit) { VkResult err; bool pass; @@ -3009,142 +1886,6 @@ TEST_F(VkLayerTest, SubmitSignaledFence) { m_errorMonitor->VerifyFound(); } -// This is a positive test. We used to expect error in this case but spec now -// allows it -TEST_F(VkLayerTest, ResetUnsignaledFence) { - m_errorMonitor->ExpectSuccess(); - vk_testing::Fence testFence; - VkFenceCreateInfo fenceInfo = {}; - fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - fenceInfo.pNext = NULL; - - ASSERT_NO_FATAL_FAILURE(InitState()); - testFence.init(*m_device, fenceInfo); - VkFence fences[1] = {testFence.handle()}; - VkResult result = vkResetFences(m_device->device(), 1, fences); - ASSERT_VK_SUCCESS(result); - - m_errorMonitor->VerifyNotFound(); -} -#if 0 // A few devices have issues with this test so disabling for now -TEST_F(VkLayerTest, LongFenceChain) -{ - m_errorMonitor->ExpectSuccess(); - - ASSERT_NO_FATAL_FAILURE(InitState()); - VkResult err; - - std::vector<VkFence> fences; - - const int chainLength = 32768; - - for (int i = 0; i < chainLength; i++) { - VkFenceCreateInfo fci = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr, 0 }; - VkFence fence; - err = vkCreateFence(m_device->device(), &fci, nullptr, &fence); - ASSERT_VK_SUCCESS(err); - - fences.push_back(fence); - - VkSubmitInfo si = { VK_STRUCTURE_TYPE_SUBMIT_INFO, nullptr, 0, nullptr, nullptr, - 0, nullptr, 0, nullptr }; - err = vkQueueSubmit(m_device->m_queue, 1, &si, fence); - ASSERT_VK_SUCCESS(err); - - } - - // BOOM, stack overflow. - vkWaitForFences(m_device->device(), 1, &fences.back(), VK_TRUE, UINT64_MAX); - - for (auto fence : fences) - vkDestroyFence(m_device->device(), fence, nullptr); - - m_errorMonitor->VerifyNotFound(); -} -#endif -TEST_F(VkLayerTest, CommandBufferSimultaneousUseSync) { - m_errorMonitor->ExpectSuccess(); - - ASSERT_NO_FATAL_FAILURE(InitState()); - VkResult err; - - // Record (empty!) command buffer that can be submitted multiple times - // simultaneously. - VkCommandBufferBeginInfo cbbi = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, nullptr, - VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, nullptr}; - m_commandBuffer->BeginCommandBuffer(&cbbi); - m_commandBuffer->EndCommandBuffer(); - - VkFenceCreateInfo fci = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr, 0}; - VkFence fence; - err = vkCreateFence(m_device->device(), &fci, nullptr, &fence); - ASSERT_VK_SUCCESS(err); - - VkSemaphoreCreateInfo sci = {VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, nullptr, 0}; - VkSemaphore s1, s2; - err = vkCreateSemaphore(m_device->device(), &sci, nullptr, &s1); - ASSERT_VK_SUCCESS(err); - err = vkCreateSemaphore(m_device->device(), &sci, nullptr, &s2); - ASSERT_VK_SUCCESS(err); - - // Submit CB once signaling s1, with fence so we can roll forward to its retirement. - VkSubmitInfo si = {VK_STRUCTURE_TYPE_SUBMIT_INFO, nullptr, 0, nullptr, nullptr, 1, &m_commandBuffer->handle(), 1, &s1}; - err = vkQueueSubmit(m_device->m_queue, 1, &si, fence); - ASSERT_VK_SUCCESS(err); - - // Submit CB again, signaling s2. - si.pSignalSemaphores = &s2; - err = vkQueueSubmit(m_device->m_queue, 1, &si, VK_NULL_HANDLE); - ASSERT_VK_SUCCESS(err); - - // Wait for fence. - err = vkWaitForFences(m_device->device(), 1, &fence, VK_TRUE, UINT64_MAX); - ASSERT_VK_SUCCESS(err); - - // CB is still in flight from second submission, but semaphore s1 is no - // longer in flight. delete it. - vkDestroySemaphore(m_device->device(), s1, nullptr); - - m_errorMonitor->VerifyNotFound(); - - // Force device idle and clean up remaining objects - vkDeviceWaitIdle(m_device->device()); - vkDestroySemaphore(m_device->device(), s2, nullptr); - vkDestroyFence(m_device->device(), fence, nullptr); -} - -TEST_F(VkLayerTest, FenceCreateSignaledWaitHandling) { - m_errorMonitor->ExpectSuccess(); - - ASSERT_NO_FATAL_FAILURE(InitState()); - VkResult err; - - // A fence created signaled - VkFenceCreateInfo fci1 = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr, VK_FENCE_CREATE_SIGNALED_BIT}; - VkFence f1; - err = vkCreateFence(m_device->device(), &fci1, nullptr, &f1); - ASSERT_VK_SUCCESS(err); - - // A fence created not - VkFenceCreateInfo fci2 = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr, 0}; - VkFence f2; - err = vkCreateFence(m_device->device(), &fci2, nullptr, &f2); - ASSERT_VK_SUCCESS(err); - - // Submit the unsignaled fence - VkSubmitInfo si = {VK_STRUCTURE_TYPE_SUBMIT_INFO, nullptr, 0, nullptr, nullptr, 0, nullptr, 0, nullptr}; - err = vkQueueSubmit(m_device->m_queue, 1, &si, f2); - - // Wait on both fences, with signaled first. - VkFence fences[] = {f1, f2}; - vkWaitForFences(m_device->device(), 2, fences, VK_TRUE, UINT64_MAX); - - // Should have both retired! - vkDestroyFence(m_device->device(), f1, nullptr); - vkDestroyFence(m_device->device(), f2, nullptr); - - m_errorMonitor->VerifyNotFound(); -} TEST_F(VkLayerTest, InvalidUsageBits) { TEST_DESCRIPTION("Specify wrong usage for image then create conflicting view of image " @@ -3200,32 +1941,7 @@ TEST_F(VkLayerTest, InvalidUsageBits) { m_errorMonitor->VerifyFound(); } -TEST_F(VkLayerTest, ValidUsage) { - TEST_DESCRIPTION("Verify that creating an image view from an image with valid usage " - "doesn't generate validation errors"); - ASSERT_NO_FATAL_FAILURE(InitState()); - - m_errorMonitor->ExpectSuccess(); - // Verify that we can create a view with usage INPUT_ATTACHMENT - VkImageObj image(m_device); - image.init(128, 128, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, VK_IMAGE_TILING_OPTIMAL, 0); - ASSERT_TRUE(image.initialized()); - VkImageView imageView; - VkImageViewCreateInfo ivci = {}; - ivci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - ivci.image = image.handle(); - ivci.viewType = VK_IMAGE_VIEW_TYPE_2D; - ivci.format = VK_FORMAT_R8G8B8A8_UNORM; - ivci.subresourceRange.layerCount = 1; - ivci.subresourceRange.baseMipLevel = 0; - ivci.subresourceRange.levelCount = 1; - ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - - vkCreateImageView(m_device->device(), &ivci, NULL, &imageView); - m_errorMonitor->VerifyNotFound(); - vkDestroyImageView(m_device->device(), imageView, NULL); -} #endif // MEM_TRACKER_TESTS #if OBJ_TRACKER_TESTS @@ -3480,98 +2196,6 @@ TEST_F(VkLayerTest, PipelineNotBound) { vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL); } -// This is a positive test. No failures are expected. -TEST_F(VkLayerTest, BindSparse) { - TEST_DESCRIPTION("Bind 2 memory ranges to one image using vkQueueBindSparse, destroy the image" - "and then free the memory"); - - ASSERT_NO_FATAL_FAILURE(InitState()); - - auto index = m_device->graphics_queue_node_index_; - if (!(m_device->queue_props[index].queueFlags & VK_QUEUE_SPARSE_BINDING_BIT)) - return; - - m_errorMonitor->ExpectSuccess(); - - VkImage image; - VkImageCreateInfo image_create_info = {}; - image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - image_create_info.pNext = NULL; - image_create_info.imageType = VK_IMAGE_TYPE_2D; - image_create_info.format = VK_FORMAT_B8G8R8A8_UNORM; - image_create_info.extent.width = 64; - image_create_info.extent.height = 64; - image_create_info.extent.depth = 1; - image_create_info.mipLevels = 1; - image_create_info.arrayLayers = 1; - image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; - image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; - image_create_info.usage = VK_IMAGE_USAGE_STORAGE_BIT; - image_create_info.flags = VK_IMAGE_CREATE_SPARSE_BINDING_BIT; - VkResult err = vkCreateImage(m_device->device(), &image_create_info, NULL, &image); - ASSERT_VK_SUCCESS(err); - - VkMemoryRequirements memory_reqs; - VkDeviceMemory memory_one, memory_two; - bool pass; - VkMemoryAllocateInfo memory_info = {}; - memory_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - memory_info.pNext = NULL; - memory_info.allocationSize = 0; - memory_info.memoryTypeIndex = 0; - vkGetImageMemoryRequirements(m_device->device(), image, &memory_reqs); - // Find an image big enough to allow sparse mapping of 2 memory regions - // Increase the image size until it is at least twice the - // size of the required alignment, to ensure we can bind both - // allocated memory blocks to the image on aligned offsets. - while (memory_reqs.size < (memory_reqs.alignment * 2)) { - vkDestroyImage(m_device->device(), image, nullptr); - image_create_info.extent.width *= 2; - image_create_info.extent.height *= 2; - err = vkCreateImage(m_device->device(), &image_create_info, nullptr, &image); - ASSERT_VK_SUCCESS(err); - vkGetImageMemoryRequirements(m_device->device(), image, &memory_reqs); - } - // Allocate 2 memory regions of minimum alignment size, bind one at 0, the other - // at the end of the first - memory_info.allocationSize = memory_reqs.alignment; - pass = m_device->phy().set_memory_type(memory_reqs.memoryTypeBits, &memory_info, 0); - ASSERT_TRUE(pass); - err = vkAllocateMemory(m_device->device(), &memory_info, NULL, &memory_one); - ASSERT_VK_SUCCESS(err); - err = vkAllocateMemory(m_device->device(), &memory_info, NULL, &memory_two); - ASSERT_VK_SUCCESS(err); - VkSparseMemoryBind binds[2]; - binds[0].flags = 0; - binds[0].memory = memory_one; - binds[0].memoryOffset = 0; - binds[0].resourceOffset = 0; - binds[0].size = memory_info.allocationSize; - binds[1].flags = 0; - binds[1].memory = memory_two; - binds[1].memoryOffset = 0; - binds[1].resourceOffset = memory_info.allocationSize; - binds[1].size = memory_info.allocationSize; - - VkSparseImageOpaqueMemoryBindInfo opaqueBindInfo; - opaqueBindInfo.image = image; - opaqueBindInfo.bindCount = 2; - opaqueBindInfo.pBinds = binds; - - VkFence fence = VK_NULL_HANDLE; - VkBindSparseInfo bindSparseInfo = {}; - bindSparseInfo.sType = VK_STRUCTURE_TYPE_BIND_SPARSE_INFO; - bindSparseInfo.imageOpaqueBindCount = 1; - bindSparseInfo.pImageOpaqueBinds = &opaqueBindInfo; - - vkQueueBindSparse(m_device->m_queue, 1, &bindSparseInfo, fence); - vkQueueWaitIdle(m_device->m_queue); - vkDestroyImage(m_device->device(), image, NULL); - vkFreeMemory(m_device->device(), memory_one, NULL); - vkFreeMemory(m_device->device(), memory_two, NULL); - m_errorMonitor->VerifyNotFound(); -} - TEST_F(VkLayerTest, BindImageInvalidMemoryType) { VkResult err; @@ -4155,265 +2779,6 @@ TEST_F(VkLayerTest, MismatchedQueueFamiliesOnSubmit) { m_errorMonitor->VerifyFound(); } -TEST_F(VkLayerTest, RenderPassInitialLayoutUndefined) { - TEST_DESCRIPTION("Ensure that CmdBeginRenderPass with an attachment's " - "initialLayout of VK_IMAGE_LAYOUT_UNDEFINED works when " - "the command buffer has prior knowledge of that " - "attachment's layout."); - - m_errorMonitor->ExpectSuccess(); - - ASSERT_NO_FATAL_FAILURE(InitState()); - - // A renderpass with one color attachment. - VkAttachmentDescription attachment = {0, - VK_FORMAT_R8G8B8A8_UNORM, - VK_SAMPLE_COUNT_1_BIT, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, - VK_ATTACHMENT_STORE_OP_STORE, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, - VK_ATTACHMENT_STORE_OP_DONT_CARE, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; - - VkAttachmentReference att_ref = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; - - VkSubpassDescription subpass = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 1, &att_ref, nullptr, nullptr, 0, nullptr}; - - VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 1, &attachment, 1, &subpass, 0, nullptr}; - - VkRenderPass rp; - VkResult err = vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); - ASSERT_VK_SUCCESS(err); - - // A compatible framebuffer. - VkImageObj image(m_device); - image.init(32, 32, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_TILING_OPTIMAL, 0); - ASSERT_TRUE(image.initialized()); - - VkImageViewCreateInfo ivci = { - VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - nullptr, - 0, - image.handle(), - VK_IMAGE_VIEW_TYPE_2D, - VK_FORMAT_R8G8B8A8_UNORM, - {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, - VK_COMPONENT_SWIZZLE_IDENTITY}, - {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}, - }; - VkImageView view; - err = vkCreateImageView(m_device->device(), &ivci, nullptr, &view); - ASSERT_VK_SUCCESS(err); - - VkFramebufferCreateInfo fci = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, nullptr, 0, rp, 1, &view, 32, 32, 1}; - VkFramebuffer fb; - err = vkCreateFramebuffer(m_device->device(), &fci, nullptr, &fb); - ASSERT_VK_SUCCESS(err); - - // Record a single command buffer which uses this renderpass twice. The - // bug is triggered at the beginning of the second renderpass, when the - // command buffer already has a layout recorded for the attachment. - VkRenderPassBeginInfo rpbi = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, nullptr, rp, fb, {{0, 0}, {32, 32}}, 0, nullptr}; - BeginCommandBuffer(); - vkCmdBeginRenderPass(m_commandBuffer->handle(), &rpbi, VK_SUBPASS_CONTENTS_INLINE); - vkCmdEndRenderPass(m_commandBuffer->handle()); - vkCmdBeginRenderPass(m_commandBuffer->handle(), &rpbi, VK_SUBPASS_CONTENTS_INLINE); - - m_errorMonitor->VerifyNotFound(); - - vkCmdEndRenderPass(m_commandBuffer->handle()); - EndCommandBuffer(); - - vkDestroyFramebuffer(m_device->device(), fb, nullptr); - vkDestroyRenderPass(m_device->device(), rp, nullptr); - vkDestroyImageView(m_device->device(), view, nullptr); -} - -TEST_F(VkLayerTest, FramebufferBindingDestroyCommandPool) { - TEST_DESCRIPTION("This test should pass. Create a Framebuffer and " - "command buffer, bind them together, then destroy " - "command pool and framebuffer and verify there are no " - "errors."); - - m_errorMonitor->ExpectSuccess(); - - ASSERT_NO_FATAL_FAILURE(InitState()); - - // A renderpass with one color attachment. - VkAttachmentDescription attachment = {0, - VK_FORMAT_R8G8B8A8_UNORM, - VK_SAMPLE_COUNT_1_BIT, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, - VK_ATTACHMENT_STORE_OP_STORE, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, - VK_ATTACHMENT_STORE_OP_DONT_CARE, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; - - VkAttachmentReference att_ref = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; - - VkSubpassDescription subpass = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 1, &att_ref, nullptr, nullptr, 0, nullptr}; - - VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 1, &attachment, 1, &subpass, 0, nullptr}; - - VkRenderPass rp; - VkResult err = vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); - ASSERT_VK_SUCCESS(err); - - // A compatible framebuffer. - VkImageObj image(m_device); - image.init(32, 32, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_TILING_OPTIMAL, 0); - ASSERT_TRUE(image.initialized()); - - VkImageViewCreateInfo ivci = { - VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - nullptr, - 0, - image.handle(), - VK_IMAGE_VIEW_TYPE_2D, - VK_FORMAT_R8G8B8A8_UNORM, - {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, - VK_COMPONENT_SWIZZLE_IDENTITY}, - {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}, - }; - VkImageView view; - err = vkCreateImageView(m_device->device(), &ivci, nullptr, &view); - ASSERT_VK_SUCCESS(err); - - VkFramebufferCreateInfo fci = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, nullptr, 0, rp, 1, &view, 32, 32, 1}; - VkFramebuffer fb; - err = vkCreateFramebuffer(m_device->device(), &fci, nullptr, &fb); - ASSERT_VK_SUCCESS(err); - - // Explicitly create a command buffer to bind the FB to so that we can then - // destroy the command pool in order to implicitly free command buffer - VkCommandPool command_pool; - VkCommandPoolCreateInfo pool_create_info{}; - pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_; - pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - vkCreateCommandPool(m_device->device(), &pool_create_info, nullptr, &command_pool); - - VkCommandBuffer command_buffer; - VkCommandBufferAllocateInfo command_buffer_allocate_info{}; - command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - command_buffer_allocate_info.commandPool = command_pool; - command_buffer_allocate_info.commandBufferCount = 1; - command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - vkAllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, &command_buffer); - - // Begin our cmd buffer with renderpass using our framebuffer - VkRenderPassBeginInfo rpbi = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, nullptr, rp, fb, {{0, 0}, {32, 32}}, 0, nullptr}; - VkCommandBufferBeginInfo begin_info{}; - begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - vkBeginCommandBuffer(command_buffer, &begin_info); - - vkCmdBeginRenderPass(command_buffer, &rpbi, VK_SUBPASS_CONTENTS_INLINE); - vkCmdEndRenderPass(command_buffer); - vkEndCommandBuffer(command_buffer); - vkDestroyImageView(m_device->device(), view, nullptr); - // Destroy command pool to implicitly free command buffer - vkDestroyCommandPool(m_device->device(), command_pool, NULL); - vkDestroyFramebuffer(m_device->device(), fb, nullptr); - vkDestroyRenderPass(m_device->device(), rp, nullptr); - m_errorMonitor->VerifyNotFound(); -} - -TEST_F(VkLayerTest, RenderPassSubpassZeroTransitionsApplied) { - TEST_DESCRIPTION("Ensure that CmdBeginRenderPass applies the layout " - "transitions for the first subpass"); - - m_errorMonitor->ExpectSuccess(); - - ASSERT_NO_FATAL_FAILURE(InitState()); - - // A renderpass with one color attachment. - VkAttachmentDescription attachment = {0, - VK_FORMAT_R8G8B8A8_UNORM, - VK_SAMPLE_COUNT_1_BIT, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, - VK_ATTACHMENT_STORE_OP_STORE, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, - VK_ATTACHMENT_STORE_OP_DONT_CARE, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; - - VkAttachmentReference att_ref = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; - - VkSubpassDescription subpass = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 1, &att_ref, nullptr, nullptr, 0, nullptr}; - - VkSubpassDependency dep = {0, - 0, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - VK_DEPENDENCY_BY_REGION_BIT}; - - VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 1, &attachment, 1, &subpass, 1, &dep}; - - VkResult err; - VkRenderPass rp; - err = vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); - ASSERT_VK_SUCCESS(err); - - // A compatible framebuffer. - VkImageObj image(m_device); - image.init(32, 32, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_TILING_OPTIMAL, 0); - ASSERT_TRUE(image.initialized()); - - VkImageViewCreateInfo ivci = { - VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - nullptr, - 0, - image.handle(), - VK_IMAGE_VIEW_TYPE_2D, - VK_FORMAT_R8G8B8A8_UNORM, - {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, - VK_COMPONENT_SWIZZLE_IDENTITY}, - {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}, - }; - VkImageView view; - err = vkCreateImageView(m_device->device(), &ivci, nullptr, &view); - ASSERT_VK_SUCCESS(err); - - VkFramebufferCreateInfo fci = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, nullptr, 0, rp, 1, &view, 32, 32, 1}; - VkFramebuffer fb; - err = vkCreateFramebuffer(m_device->device(), &fci, nullptr, &fb); - ASSERT_VK_SUCCESS(err); - - // Record a single command buffer which issues a pipeline barrier w/ - // image memory barrier for the attachment. This detects the previously - // missing tracking of the subpass layout by throwing a validation error - // if it doesn't occur. - VkRenderPassBeginInfo rpbi = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, nullptr, rp, fb, {{0, 0}, {32, 32}}, 0, nullptr}; - BeginCommandBuffer(); - vkCmdBeginRenderPass(m_commandBuffer->handle(), &rpbi, VK_SUBPASS_CONTENTS_INLINE); - - VkImageMemoryBarrier imb = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - nullptr, - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_QUEUE_FAMILY_IGNORED, - VK_QUEUE_FAMILY_IGNORED, - image.handle(), - {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}}; - vkCmdPipelineBarrier(m_commandBuffer->handle(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_DEPENDENCY_BY_REGION_BIT, 0, nullptr, 0, nullptr, 1, - &imb); - - vkCmdEndRenderPass(m_commandBuffer->handle()); - m_errorMonitor->VerifyNotFound(); - EndCommandBuffer(); - - vkDestroyFramebuffer(m_device->device(), fb, nullptr); - vkDestroyRenderPass(m_device->device(), rp, nullptr); - vkDestroyImageView(m_device->device(), view, nullptr); -} - TEST_F(VkLayerTest, RenderPassPipelineSubpassMismatch) { TEST_DESCRIPTION("Use a pipeline for the wrong subpass in a render pass instance"); ASSERT_NO_FATAL_FAILURE(InitState()); @@ -4529,111 +2894,6 @@ TEST_F(VkLayerTest, RenderPassPipelineSubpassMismatch) { vkDestroyRenderPass(m_device->device(), rp, nullptr); } -TEST_F(VkLayerTest, DepthStencilLayoutTransitionForDepthOnlyImageview) { - TEST_DESCRIPTION("Validate that when an imageView of a depth/stencil image " - "is used as a depth/stencil framebuffer attachment, the " - "aspectMask is ignored and both depth and stencil image " - "subresources are used."); - - VkFormatProperties format_properties; - vkGetPhysicalDeviceFormatProperties(gpu(), VK_FORMAT_D32_SFLOAT_S8_UINT, &format_properties); - if (!(format_properties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) { - return; - } - - m_errorMonitor->ExpectSuccess(); - - ASSERT_NO_FATAL_FAILURE(InitState()); - - VkAttachmentDescription attachment = {0, - VK_FORMAT_D32_SFLOAT_S8_UINT, - VK_SAMPLE_COUNT_1_BIT, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, - VK_ATTACHMENT_STORE_OP_STORE, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, - VK_ATTACHMENT_STORE_OP_DONT_CARE, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}; - - VkAttachmentReference att_ref = {0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}; - - VkSubpassDescription subpass = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 0, nullptr, nullptr, &att_ref, 0, nullptr}; - - VkSubpassDependency dep = {0, - 0, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - VK_DEPENDENCY_BY_REGION_BIT}; - - VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 1, &attachment, 1, &subpass, 1, &dep}; - - VkResult err; - VkRenderPass rp; - err = vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); - ASSERT_VK_SUCCESS(err); - - VkImageObj image(m_device); - image.init_no_layout(32, 32, VK_FORMAT_D32_SFLOAT_S8_UINT, - 0x26, // usage - VK_IMAGE_TILING_OPTIMAL, 0); - ASSERT_TRUE(image.initialized()); - image.SetLayout(0x6, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); - - VkImageViewCreateInfo ivci = { - VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - nullptr, - 0, - image.handle(), - VK_IMAGE_VIEW_TYPE_2D, - VK_FORMAT_D32_SFLOAT_S8_UINT, - {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A}, - {0x2, 0, 1, 0, 1}, - }; - VkImageView view; - err = vkCreateImageView(m_device->device(), &ivci, nullptr, &view); - ASSERT_VK_SUCCESS(err); - - VkFramebufferCreateInfo fci = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, nullptr, 0, rp, 1, &view, 32, 32, 1}; - VkFramebuffer fb; - err = vkCreateFramebuffer(m_device->device(), &fci, nullptr, &fb); - ASSERT_VK_SUCCESS(err); - - VkRenderPassBeginInfo rpbi = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, nullptr, rp, fb, {{0, 0}, {32, 32}}, 0, nullptr}; - BeginCommandBuffer(); - vkCmdBeginRenderPass(m_commandBuffer->handle(), &rpbi, VK_SUBPASS_CONTENTS_INLINE); - - VkImageMemoryBarrier imb = {}; - imb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - imb.pNext = nullptr; - imb.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - imb.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - imb.oldLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - imb.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - imb.srcQueueFamilyIndex = 0; - imb.dstQueueFamilyIndex = 0; - imb.image = image.handle(); - imb.subresourceRange.aspectMask = 0x6; - imb.subresourceRange.baseMipLevel = 0; - imb.subresourceRange.levelCount = 0x1; - imb.subresourceRange.baseArrayLayer = 0; - imb.subresourceRange.layerCount = 0x1; - - vkCmdPipelineBarrier(m_commandBuffer->handle(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_DEPENDENCY_BY_REGION_BIT, 0, nullptr, 0, nullptr, 1, - &imb); - - vkCmdEndRenderPass(m_commandBuffer->handle()); - EndCommandBuffer(); - QueueCommandBuffer(false); - m_errorMonitor->VerifyNotFound(); - - vkDestroyFramebuffer(m_device->device(), fb, nullptr); - vkDestroyRenderPass(m_device->device(), rp, nullptr); - vkDestroyImageView(m_device->device(), view, nullptr); -} - TEST_F(VkLayerTest, RenderPassInvalidRenderArea) { TEST_DESCRIPTION("Generate INVALID_RENDER_AREA error by beginning renderpass" "with extent outside of framebuffer"); @@ -4710,213 +2970,6 @@ TEST_F(VkLayerTest, RenderPassDepthStencilAttachmentUnused) { m_errorMonitor->VerifyFound(); } -TEST_F(VkLayerTest, RenderPassTransitionsAttachmentUnused) { - TEST_DESCRIPTION("Ensure that layout transitions work correctly without " - "errors, when an attachment reference is " - "VK_ATTACHMENT_UNUSED"); - - m_errorMonitor->ExpectSuccess(); - - ASSERT_NO_FATAL_FAILURE(InitState()); - - // A renderpass with no attachments - VkAttachmentReference att_ref = {VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; - - VkSubpassDescription subpass = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 1, &att_ref, nullptr, nullptr, 0, nullptr}; - - VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 0, nullptr, 1, &subpass, 0, nullptr}; - - VkRenderPass rp; - VkResult err = vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); - ASSERT_VK_SUCCESS(err); - - // A compatible framebuffer. - VkFramebufferCreateInfo fci = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, nullptr, 0, rp, 0, nullptr, 32, 32, 1}; - VkFramebuffer fb; - err = vkCreateFramebuffer(m_device->device(), &fci, nullptr, &fb); - ASSERT_VK_SUCCESS(err); - - // Record a command buffer which just begins and ends the renderpass. The - // bug manifests in BeginRenderPass. - VkRenderPassBeginInfo rpbi = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, nullptr, rp, fb, {{0, 0}, {32, 32}}, 0, nullptr}; - BeginCommandBuffer(); - vkCmdBeginRenderPass(m_commandBuffer->handle(), &rpbi, VK_SUBPASS_CONTENTS_INLINE); - vkCmdEndRenderPass(m_commandBuffer->handle()); - m_errorMonitor->VerifyNotFound(); - EndCommandBuffer(); - - vkDestroyFramebuffer(m_device->device(), fb, nullptr); - vkDestroyRenderPass(m_device->device(), rp, nullptr); -} - -// This is a positive test. No errors are expected. -TEST_F(VkLayerTest, StencilLoadOp) { - TEST_DESCRIPTION("Create a stencil-only attachment with a LOAD_OP set to " - "CLEAR. stencil[Load|Store]Op used to be ignored."); - VkResult result = VK_SUCCESS; - VkImageFormatProperties formatProps; - vkGetPhysicalDeviceImageFormatProperties(gpu(), VK_FORMAT_D24_UNORM_S8_UINT, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 0, - &formatProps); - if (formatProps.maxExtent.width < 100 || formatProps.maxExtent.height < 100) { - return; - } - - ASSERT_NO_FATAL_FAILURE(InitState()); - VkFormat depth_stencil_fmt = VK_FORMAT_D24_UNORM_S8_UINT; - m_depthStencil->Init(m_device, 100, 100, depth_stencil_fmt, - VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT); - VkAttachmentDescription att = {}; - VkAttachmentReference ref = {}; - att.format = depth_stencil_fmt; - att.samples = VK_SAMPLE_COUNT_1_BIT; - att.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - att.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - att.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - att.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; - att.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - att.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - - VkClearValue clear; - clear.depthStencil.depth = 1.0; - clear.depthStencil.stencil = 0; - ref.attachment = 0; - ref.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - - VkSubpassDescription subpass = {}; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.flags = 0; - subpass.inputAttachmentCount = 0; - subpass.pInputAttachments = NULL; - subpass.colorAttachmentCount = 0; - subpass.pColorAttachments = NULL; - subpass.pResolveAttachments = NULL; - subpass.pDepthStencilAttachment = &ref; - subpass.preserveAttachmentCount = 0; - subpass.pPreserveAttachments = NULL; - - VkRenderPass rp; - VkRenderPassCreateInfo rp_info = {}; - rp_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - rp_info.attachmentCount = 1; - rp_info.pAttachments = &att; - rp_info.subpassCount = 1; - rp_info.pSubpasses = &subpass; - result = vkCreateRenderPass(device(), &rp_info, NULL, &rp); - ASSERT_VK_SUCCESS(result); - - VkImageView *depthView = m_depthStencil->BindInfo(); - VkFramebufferCreateInfo fb_info = {}; - fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - fb_info.pNext = NULL; - fb_info.renderPass = rp; - fb_info.attachmentCount = 1; - fb_info.pAttachments = depthView; - fb_info.width = 100; - fb_info.height = 100; - fb_info.layers = 1; - VkFramebuffer fb; - result = vkCreateFramebuffer(device(), &fb_info, NULL, &fb); - ASSERT_VK_SUCCESS(result); - - VkRenderPassBeginInfo rpbinfo = {}; - rpbinfo.clearValueCount = 1; - rpbinfo.pClearValues = &clear; - rpbinfo.pNext = NULL; - rpbinfo.renderPass = rp; - rpbinfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - rpbinfo.renderArea.extent.width = 100; - rpbinfo.renderArea.extent.height = 100; - rpbinfo.renderArea.offset.x = 0; - rpbinfo.renderArea.offset.y = 0; - rpbinfo.framebuffer = fb; - - VkFence fence = {}; - VkFenceCreateInfo fence_ci = {}; - fence_ci.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - fence_ci.pNext = nullptr; - fence_ci.flags = 0; - result = vkCreateFence(m_device->device(), &fence_ci, nullptr, &fence); - ASSERT_VK_SUCCESS(result); - - m_commandBuffer->BeginCommandBuffer(); - m_commandBuffer->BeginRenderPass(rpbinfo); - m_commandBuffer->EndRenderPass(); - m_commandBuffer->EndCommandBuffer(); - m_commandBuffer->QueueCommandBuffer(fence); - - VkImageObj destImage(m_device); - destImage.init(100, 100, depth_stencil_fmt, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, - VK_IMAGE_TILING_OPTIMAL, 0); - VkImageMemoryBarrier barrier = {}; - VkImageSubresourceRange range; - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; - barrier.oldLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - barrier.image = m_depthStencil->handle(); - range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - range.baseMipLevel = 0; - range.levelCount = 1; - range.baseArrayLayer = 0; - range.layerCount = 1; - barrier.subresourceRange = range; - vkWaitForFences(m_device->device(), 1, &fence, VK_TRUE, UINT64_MAX); - VkCommandBufferObj cmdbuf(m_device, m_commandPool); - cmdbuf.BeginCommandBuffer(); - cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, - &barrier); - barrier.srcAccessMask = 0; - barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - barrier.image = destImage.handle(); - barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, - &barrier); - VkImageCopy cregion; - cregion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - cregion.srcSubresource.mipLevel = 0; - cregion.srcSubresource.baseArrayLayer = 0; - cregion.srcSubresource.layerCount = 1; - cregion.srcOffset.x = 0; - cregion.srcOffset.y = 0; - cregion.srcOffset.z = 0; - cregion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - cregion.dstSubresource.mipLevel = 0; - cregion.dstSubresource.baseArrayLayer = 0; - cregion.dstSubresource.layerCount = 1; - cregion.dstOffset.x = 0; - cregion.dstOffset.y = 0; - cregion.dstOffset.z = 0; - cregion.extent.width = 100; - cregion.extent.height = 100; - cregion.extent.depth = 1; - cmdbuf.CopyImage(m_depthStencil->handle(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, destImage.handle(), - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &cregion); - cmdbuf.EndCommandBuffer(); - - VkSubmitInfo submit_info; - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.pNext = NULL; - submit_info.waitSemaphoreCount = 0; - submit_info.pWaitSemaphores = NULL; - submit_info.pWaitDstStageMask = NULL; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &cmdbuf.handle(); - submit_info.signalSemaphoreCount = 0; - submit_info.pSignalSemaphores = NULL; - - m_errorMonitor->ExpectSuccess(); - vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); - m_errorMonitor->VerifyNotFound(); - - vkQueueWaitIdle(m_device->m_queue); - vkDestroyFence(m_device->device(), fence, nullptr); - vkDestroyRenderPass(m_device->device(), rp, nullptr); - vkDestroyFramebuffer(m_device->device(), fb, nullptr); -} - TEST_F(VkLayerTest, UnusedPreserveAttachment) { TEST_DESCRIPTION("Create a framebuffer where a subpass has a preserve " "attachment reference of VK_ATTACHMENT_UNUSED"); @@ -5294,1300 +3347,6 @@ TEST_F(VkLayerTest, FramebufferCreateErrors) { vkDestroyRenderPass(m_device->device(), rp, NULL); } -// This is a positive test. No errors should be generated. -TEST_F(VkLayerTest, WaitEventThenSet) { - TEST_DESCRIPTION("Wait on a event then set it after the wait has been submitted."); - - m_errorMonitor->ExpectSuccess(); - ASSERT_NO_FATAL_FAILURE(InitState()); - - VkEvent event; - VkEventCreateInfo event_create_info{}; - event_create_info.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO; - vkCreateEvent(m_device->device(), &event_create_info, nullptr, &event); - - VkCommandPool command_pool; - VkCommandPoolCreateInfo pool_create_info{}; - pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_; - pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - vkCreateCommandPool(m_device->device(), &pool_create_info, nullptr, &command_pool); - - VkCommandBuffer command_buffer; - VkCommandBufferAllocateInfo command_buffer_allocate_info{}; - command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - command_buffer_allocate_info.commandPool = command_pool; - command_buffer_allocate_info.commandBufferCount = 1; - command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - vkAllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, &command_buffer); - - VkQueue queue = VK_NULL_HANDLE; - vkGetDeviceQueue(m_device->device(), m_device->graphics_queue_node_index_, 0, &queue); - - { - VkCommandBufferBeginInfo begin_info{}; - begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - vkBeginCommandBuffer(command_buffer, &begin_info); - - vkCmdWaitEvents(command_buffer, 1, &event, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, nullptr, 0, - nullptr, 0, nullptr); - vkCmdResetEvent(command_buffer, event, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); - vkEndCommandBuffer(command_buffer); - } - { - VkSubmitInfo submit_info{}; - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &command_buffer; - submit_info.signalSemaphoreCount = 0; - submit_info.pSignalSemaphores = nullptr; - vkQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE); - } - { vkSetEvent(m_device->device(), event); } - - vkQueueWaitIdle(queue); - - vkDestroyEvent(m_device->device(), event, nullptr); - vkFreeCommandBuffers(m_device->device(), command_pool, 1, &command_buffer); - vkDestroyCommandPool(m_device->device(), command_pool, NULL); - - m_errorMonitor->VerifyNotFound(); -} -// This is a positive test. No errors should be generated. -TEST_F(VkLayerTest, QueryAndCopySecondaryCommandBuffers) { - TEST_DESCRIPTION("Issue a query on a secondary command buffery and copy it on a primary."); - - ASSERT_NO_FATAL_FAILURE(InitState()); - if ((m_device->queue_props.empty()) || (m_device->queue_props[0].queueCount < 2)) - return; - - m_errorMonitor->ExpectSuccess(); - - VkQueryPool query_pool; - VkQueryPoolCreateInfo query_pool_create_info{}; - query_pool_create_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; - query_pool_create_info.queryType = VK_QUERY_TYPE_TIMESTAMP; - query_pool_create_info.queryCount = 1; - vkCreateQueryPool(m_device->device(), &query_pool_create_info, nullptr, &query_pool); - - VkCommandPool command_pool; - VkCommandPoolCreateInfo pool_create_info{}; - pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_; - pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - vkCreateCommandPool(m_device->device(), &pool_create_info, nullptr, &command_pool); - - VkCommandBuffer command_buffer; - VkCommandBufferAllocateInfo command_buffer_allocate_info{}; - command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - command_buffer_allocate_info.commandPool = command_pool; - command_buffer_allocate_info.commandBufferCount = 1; - command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - vkAllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, &command_buffer); - - VkCommandBuffer secondary_command_buffer; - command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY; - vkAllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, &secondary_command_buffer); - - VkQueue queue = VK_NULL_HANDLE; - vkGetDeviceQueue(m_device->device(), m_device->graphics_queue_node_index_, 1, &queue); - - uint32_t qfi = 0; - VkBufferCreateInfo buff_create_info = {}; - buff_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - buff_create_info.size = 1024; - buff_create_info.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT; - buff_create_info.queueFamilyIndexCount = 1; - buff_create_info.pQueueFamilyIndices = &qfi; - - VkResult err; - VkBuffer buffer; - err = vkCreateBuffer(m_device->device(), &buff_create_info, NULL, &buffer); - ASSERT_VK_SUCCESS(err); - VkMemoryAllocateInfo mem_alloc = {}; - mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - mem_alloc.pNext = NULL; - mem_alloc.allocationSize = 1024; - mem_alloc.memoryTypeIndex = 0; - - VkMemoryRequirements memReqs; - vkGetBufferMemoryRequirements(m_device->device(), buffer, &memReqs); - bool pass = m_device->phy().set_memory_type(memReqs.memoryTypeBits, &mem_alloc, 0); - if (!pass) { - vkDestroyBuffer(m_device->device(), buffer, NULL); - return; - } - - VkDeviceMemory mem; - err = vkAllocateMemory(m_device->device(), &mem_alloc, NULL, &mem); - ASSERT_VK_SUCCESS(err); - err = vkBindBufferMemory(m_device->device(), buffer, mem, 0); - ASSERT_VK_SUCCESS(err); - - VkCommandBufferInheritanceInfo hinfo = {}; - hinfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; - hinfo.renderPass = VK_NULL_HANDLE; - hinfo.subpass = 0; - hinfo.framebuffer = VK_NULL_HANDLE; - hinfo.occlusionQueryEnable = VK_FALSE; - hinfo.queryFlags = 0; - hinfo.pipelineStatistics = 0; - - { - VkCommandBufferBeginInfo begin_info{}; - begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - begin_info.pInheritanceInfo = &hinfo; - vkBeginCommandBuffer(secondary_command_buffer, &begin_info); - - vkCmdResetQueryPool(secondary_command_buffer, query_pool, 0, 1); - vkCmdWriteTimestamp(secondary_command_buffer, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, query_pool, 0); - - vkEndCommandBuffer(secondary_command_buffer); - - begin_info.pInheritanceInfo = nullptr; - vkBeginCommandBuffer(command_buffer, &begin_info); - - vkCmdExecuteCommands(command_buffer, 1, &secondary_command_buffer); - vkCmdCopyQueryPoolResults(command_buffer, query_pool, 0, 1, buffer, 0, 0, 0); - - vkEndCommandBuffer(command_buffer); - } - { - VkSubmitInfo submit_info{}; - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &command_buffer; - submit_info.signalSemaphoreCount = 0; - submit_info.pSignalSemaphores = nullptr; - vkQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE); - } - - vkQueueWaitIdle(queue); - - vkDestroyQueryPool(m_device->device(), query_pool, nullptr); - vkFreeCommandBuffers(m_device->device(), command_pool, 1, &command_buffer); - vkFreeCommandBuffers(m_device->device(), command_pool, 1, &secondary_command_buffer); - vkDestroyCommandPool(m_device->device(), command_pool, NULL); - vkDestroyBuffer(m_device->device(), buffer, NULL); - vkFreeMemory(m_device->device(), mem, NULL); - - m_errorMonitor->VerifyNotFound(); -} - -// This is a positive test. No errors should be generated. -TEST_F(VkLayerTest, QueryAndCopyMultipleCommandBuffers) { - TEST_DESCRIPTION("Issue a query and copy from it on a second command buffer."); - - ASSERT_NO_FATAL_FAILURE(InitState()); - if ((m_device->queue_props.empty()) || (m_device->queue_props[0].queueCount < 2)) - return; - - m_errorMonitor->ExpectSuccess(); - - VkQueryPool query_pool; - VkQueryPoolCreateInfo query_pool_create_info{}; - query_pool_create_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; - query_pool_create_info.queryType = VK_QUERY_TYPE_TIMESTAMP; - query_pool_create_info.queryCount = 1; - vkCreateQueryPool(m_device->device(), &query_pool_create_info, nullptr, &query_pool); - - VkCommandPool command_pool; - VkCommandPoolCreateInfo pool_create_info{}; - pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_; - pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - vkCreateCommandPool(m_device->device(), &pool_create_info, nullptr, &command_pool); - - VkCommandBuffer command_buffer[2]; - VkCommandBufferAllocateInfo command_buffer_allocate_info{}; - command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - command_buffer_allocate_info.commandPool = command_pool; - command_buffer_allocate_info.commandBufferCount = 2; - command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - vkAllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, command_buffer); - - VkQueue queue = VK_NULL_HANDLE; - vkGetDeviceQueue(m_device->device(), m_device->graphics_queue_node_index_, 1, &queue); - - uint32_t qfi = 0; - VkBufferCreateInfo buff_create_info = {}; - buff_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - buff_create_info.size = 1024; - buff_create_info.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT; - buff_create_info.queueFamilyIndexCount = 1; - buff_create_info.pQueueFamilyIndices = &qfi; - - VkResult err; - VkBuffer buffer; - err = vkCreateBuffer(m_device->device(), &buff_create_info, NULL, &buffer); - ASSERT_VK_SUCCESS(err); - VkMemoryAllocateInfo mem_alloc = {}; - mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - mem_alloc.pNext = NULL; - mem_alloc.allocationSize = 1024; - mem_alloc.memoryTypeIndex = 0; - - VkMemoryRequirements memReqs; - vkGetBufferMemoryRequirements(m_device->device(), buffer, &memReqs); - bool pass = m_device->phy().set_memory_type(memReqs.memoryTypeBits, &mem_alloc, 0); - if (!pass) { - vkDestroyBuffer(m_device->device(), buffer, NULL); - return; - } - - VkDeviceMemory mem; - err = vkAllocateMemory(m_device->device(), &mem_alloc, NULL, &mem); - ASSERT_VK_SUCCESS(err); - err = vkBindBufferMemory(m_device->device(), buffer, mem, 0); - ASSERT_VK_SUCCESS(err); - - { - VkCommandBufferBeginInfo begin_info{}; - begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - vkBeginCommandBuffer(command_buffer[0], &begin_info); - - vkCmdResetQueryPool(command_buffer[0], query_pool, 0, 1); - vkCmdWriteTimestamp(command_buffer[0], VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, query_pool, 0); - - vkEndCommandBuffer(command_buffer[0]); - - vkBeginCommandBuffer(command_buffer[1], &begin_info); - - vkCmdCopyQueryPoolResults(command_buffer[1], query_pool, 0, 1, buffer, 0, 0, 0); - - vkEndCommandBuffer(command_buffer[1]); - } - { - VkSubmitInfo submit_info{}; - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.commandBufferCount = 2; - submit_info.pCommandBuffers = command_buffer; - submit_info.signalSemaphoreCount = 0; - submit_info.pSignalSemaphores = nullptr; - vkQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE); - } - - vkQueueWaitIdle(queue); - - vkDestroyQueryPool(m_device->device(), query_pool, nullptr); - vkFreeCommandBuffers(m_device->device(), command_pool, 2, command_buffer); - vkDestroyCommandPool(m_device->device(), command_pool, NULL); - vkDestroyBuffer(m_device->device(), buffer, NULL); - vkFreeMemory(m_device->device(), mem, NULL); - - m_errorMonitor->VerifyNotFound(); -} - -TEST_F(VkLayerTest, ResetEventThenSet) { - TEST_DESCRIPTION("Reset an event then set it after the reset has been submitted."); - - m_errorMonitor->ExpectSuccess(); - - ASSERT_NO_FATAL_FAILURE(InitState()); - VkEvent event; - VkEventCreateInfo event_create_info{}; - event_create_info.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO; - vkCreateEvent(m_device->device(), &event_create_info, nullptr, &event); - - VkCommandPool command_pool; - VkCommandPoolCreateInfo pool_create_info{}; - pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_; - pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - vkCreateCommandPool(m_device->device(), &pool_create_info, nullptr, &command_pool); - - VkCommandBuffer command_buffer; - VkCommandBufferAllocateInfo command_buffer_allocate_info{}; - command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - command_buffer_allocate_info.commandPool = command_pool; - command_buffer_allocate_info.commandBufferCount = 1; - command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - vkAllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, &command_buffer); - - VkQueue queue = VK_NULL_HANDLE; - vkGetDeviceQueue(m_device->device(), m_device->graphics_queue_node_index_, 0, &queue); - - { - VkCommandBufferBeginInfo begin_info{}; - begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - vkBeginCommandBuffer(command_buffer, &begin_info); - - vkCmdResetEvent(command_buffer, event, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); - vkCmdWaitEvents(command_buffer, 1, &event, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, - nullptr, 0, nullptr, 0, nullptr); - vkEndCommandBuffer(command_buffer); - } - { - VkSubmitInfo submit_info{}; - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &command_buffer; - submit_info.signalSemaphoreCount = 0; - submit_info.pSignalSemaphores = nullptr; - vkQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE); - } - { - m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "that is already in use by a " - "command buffer."); - vkSetEvent(m_device->device(), event); - m_errorMonitor->VerifyFound(); - } - - vkQueueWaitIdle(queue); - - vkDestroyEvent(m_device->device(), event, nullptr); - vkFreeCommandBuffers(m_device->device(), command_pool, 1, &command_buffer); - vkDestroyCommandPool(m_device->device(), command_pool, NULL); -} - -// This is a positive test. No errors should be generated. -TEST_F(VkLayerTest, TwoFencesThreeFrames) { - TEST_DESCRIPTION("Two command buffers with two separate fences are each " - "run through a Submit & WaitForFences cycle 3 times. This " - "previously revealed a bug so running this positive test " - "to prevent a regression."); - m_errorMonitor->ExpectSuccess(); - - ASSERT_NO_FATAL_FAILURE(InitState()); - VkQueue queue = VK_NULL_HANDLE; - vkGetDeviceQueue(m_device->device(), m_device->graphics_queue_node_index_, 0, &queue); - - static const uint32_t NUM_OBJECTS = 2; - static const uint32_t NUM_FRAMES = 3; - VkCommandBuffer cmd_buffers[NUM_OBJECTS] = {}; - VkFence fences[NUM_OBJECTS] = {}; - - VkCommandPool cmd_pool; - VkCommandPoolCreateInfo cmd_pool_ci = {}; - cmd_pool_ci.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - cmd_pool_ci.queueFamilyIndex = m_device->graphics_queue_node_index_; - cmd_pool_ci.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - VkResult err = vkCreateCommandPool(m_device->device(), &cmd_pool_ci, nullptr, &cmd_pool); - ASSERT_VK_SUCCESS(err); - - VkCommandBufferAllocateInfo cmd_buf_info = {}; - cmd_buf_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - cmd_buf_info.commandPool = cmd_pool; - cmd_buf_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - cmd_buf_info.commandBufferCount = 1; - - VkFenceCreateInfo fence_ci = {}; - fence_ci.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - fence_ci.pNext = nullptr; - fence_ci.flags = 0; - - for (uint32_t i = 0; i < NUM_OBJECTS; ++i) { - err = vkAllocateCommandBuffers(m_device->device(), &cmd_buf_info, &cmd_buffers[i]); - ASSERT_VK_SUCCESS(err); - err = vkCreateFence(m_device->device(), &fence_ci, nullptr, &fences[i]); - ASSERT_VK_SUCCESS(err); - } - - for (uint32_t frame = 0; frame < NUM_FRAMES; ++frame) { - for (uint32_t obj = 0; obj < NUM_OBJECTS; ++obj) { - // Create empty cmd buffer - VkCommandBufferBeginInfo cmdBufBeginDesc = {}; - cmdBufBeginDesc.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - - err = vkBeginCommandBuffer(cmd_buffers[obj], &cmdBufBeginDesc); - ASSERT_VK_SUCCESS(err); - err = vkEndCommandBuffer(cmd_buffers[obj]); - ASSERT_VK_SUCCESS(err); - - VkSubmitInfo submit_info = {}; - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &cmd_buffers[obj]; - // Submit cmd buffer and wait for fence - err = vkQueueSubmit(queue, 1, &submit_info, fences[obj]); - ASSERT_VK_SUCCESS(err); - err = vkWaitForFences(m_device->device(), 1, &fences[obj], VK_TRUE, UINT64_MAX); - ASSERT_VK_SUCCESS(err); - err = vkResetFences(m_device->device(), 1, &fences[obj]); - ASSERT_VK_SUCCESS(err); - } - } - m_errorMonitor->VerifyNotFound(); - vkDestroyCommandPool(m_device->device(), cmd_pool, NULL); - for (uint32_t i = 0; i < NUM_OBJECTS; ++i) { - vkDestroyFence(m_device->device(), fences[i], nullptr); - } -} -// This is a positive test. No errors should be generated. -TEST_F(VkLayerTest, TwoQueueSubmitsSeparateQueuesWithSemaphoreAndOneFenceQWI) { - - TEST_DESCRIPTION("Two command buffers, each in a separate QueueSubmit call " - "submitted on separate queues followed by a QueueWaitIdle."); - - ASSERT_NO_FATAL_FAILURE(InitState()); - if ((m_device->queue_props.empty()) || (m_device->queue_props[0].queueCount < 2)) - return; - - m_errorMonitor->ExpectSuccess(); - - VkSemaphore semaphore; - VkSemaphoreCreateInfo semaphore_create_info{}; - semaphore_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - vkCreateSemaphore(m_device->device(), &semaphore_create_info, nullptr, &semaphore); - - VkCommandPool command_pool; - VkCommandPoolCreateInfo pool_create_info{}; - pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_; - pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - vkCreateCommandPool(m_device->device(), &pool_create_info, nullptr, &command_pool); - - VkCommandBuffer command_buffer[2]; - VkCommandBufferAllocateInfo command_buffer_allocate_info{}; - command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - command_buffer_allocate_info.commandPool = command_pool; - command_buffer_allocate_info.commandBufferCount = 2; - command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - vkAllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, command_buffer); - - VkQueue queue = VK_NULL_HANDLE; - vkGetDeviceQueue(m_device->device(), m_device->graphics_queue_node_index_, 1, &queue); - - { - VkCommandBufferBeginInfo begin_info{}; - begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - vkBeginCommandBuffer(command_buffer[0], &begin_info); - - vkCmdPipelineBarrier(command_buffer[0], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, - nullptr, 0, nullptr, 0, nullptr); - - VkViewport viewport{}; - viewport.maxDepth = 1.0f; - viewport.minDepth = 0.0f; - viewport.width = 512; - viewport.height = 512; - viewport.x = 0; - viewport.y = 0; - vkCmdSetViewport(command_buffer[0], 0, 1, &viewport); - vkEndCommandBuffer(command_buffer[0]); - } - { - VkCommandBufferBeginInfo begin_info{}; - begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - vkBeginCommandBuffer(command_buffer[1], &begin_info); - - VkViewport viewport{}; - viewport.maxDepth = 1.0f; - viewport.minDepth = 0.0f; - viewport.width = 512; - viewport.height = 512; - viewport.x = 0; - viewport.y = 0; - vkCmdSetViewport(command_buffer[1], 0, 1, &viewport); - vkEndCommandBuffer(command_buffer[1]); - } - { - VkSubmitInfo submit_info{}; - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &command_buffer[0]; - submit_info.signalSemaphoreCount = 1; - submit_info.pSignalSemaphores = &semaphore; - vkQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE); - } - { - VkPipelineStageFlags flags[]{VK_PIPELINE_STAGE_ALL_COMMANDS_BIT}; - VkSubmitInfo submit_info{}; - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &command_buffer[1]; - submit_info.waitSemaphoreCount = 1; - submit_info.pWaitSemaphores = &semaphore; - submit_info.pWaitDstStageMask = flags; - vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); - } - - vkQueueWaitIdle(m_device->m_queue); - - vkDestroySemaphore(m_device->device(), semaphore, nullptr); - vkFreeCommandBuffers(m_device->device(), command_pool, 2, &command_buffer[0]); - vkDestroyCommandPool(m_device->device(), command_pool, NULL); - - m_errorMonitor->VerifyNotFound(); -} - -// This is a positive test. No errors should be generated. -TEST_F(VkLayerTest, TwoQueueSubmitsSeparateQueuesWithSemaphoreAndOneFenceQWIFence) { - - TEST_DESCRIPTION("Two command buffers, each in a separate QueueSubmit call " - "submitted on separate queues, the second having a fence" - "followed by a QueueWaitIdle."); - - ASSERT_NO_FATAL_FAILURE(InitState()); - if ((m_device->queue_props.empty()) || (m_device->queue_props[0].queueCount < 2)) - return; - - m_errorMonitor->ExpectSuccess(); - - VkFence fence; - VkFenceCreateInfo fence_create_info{}; - fence_create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - vkCreateFence(m_device->device(), &fence_create_info, nullptr, &fence); - - VkSemaphore semaphore; - VkSemaphoreCreateInfo semaphore_create_info{}; - semaphore_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - vkCreateSemaphore(m_device->device(), &semaphore_create_info, nullptr, &semaphore); - - VkCommandPool command_pool; - VkCommandPoolCreateInfo pool_create_info{}; - pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_; - pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - vkCreateCommandPool(m_device->device(), &pool_create_info, nullptr, &command_pool); - - VkCommandBuffer command_buffer[2]; - VkCommandBufferAllocateInfo command_buffer_allocate_info{}; - command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - command_buffer_allocate_info.commandPool = command_pool; - command_buffer_allocate_info.commandBufferCount = 2; - command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - vkAllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, command_buffer); - - VkQueue queue = VK_NULL_HANDLE; - vkGetDeviceQueue(m_device->device(), m_device->graphics_queue_node_index_, 1, &queue); - - { - VkCommandBufferBeginInfo begin_info{}; - begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - vkBeginCommandBuffer(command_buffer[0], &begin_info); - - vkCmdPipelineBarrier(command_buffer[0], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, - nullptr, 0, nullptr, 0, nullptr); - - VkViewport viewport{}; - viewport.maxDepth = 1.0f; - viewport.minDepth = 0.0f; - viewport.width = 512; - viewport.height = 512; - viewport.x = 0; - viewport.y = 0; - vkCmdSetViewport(command_buffer[0], 0, 1, &viewport); - vkEndCommandBuffer(command_buffer[0]); - } - { - VkCommandBufferBeginInfo begin_info{}; - begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - vkBeginCommandBuffer(command_buffer[1], &begin_info); - - VkViewport viewport{}; - viewport.maxDepth = 1.0f; - viewport.minDepth = 0.0f; - viewport.width = 512; - viewport.height = 512; - viewport.x = 0; - viewport.y = 0; - vkCmdSetViewport(command_buffer[1], 0, 1, &viewport); - vkEndCommandBuffer(command_buffer[1]); - } - { - VkSubmitInfo submit_info{}; - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &command_buffer[0]; - submit_info.signalSemaphoreCount = 1; - submit_info.pSignalSemaphores = &semaphore; - vkQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE); - } - { - VkPipelineStageFlags flags[]{VK_PIPELINE_STAGE_ALL_COMMANDS_BIT}; - VkSubmitInfo submit_info{}; - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &command_buffer[1]; - submit_info.waitSemaphoreCount = 1; - submit_info.pWaitSemaphores = &semaphore; - submit_info.pWaitDstStageMask = flags; - vkQueueSubmit(m_device->m_queue, 1, &submit_info, fence); - } - - vkQueueWaitIdle(m_device->m_queue); - - vkDestroyFence(m_device->device(), fence, nullptr); - vkDestroySemaphore(m_device->device(), semaphore, nullptr); - vkFreeCommandBuffers(m_device->device(), command_pool, 2, &command_buffer[0]); - vkDestroyCommandPool(m_device->device(), command_pool, NULL); - - m_errorMonitor->VerifyNotFound(); -} - -// This is a positive test. No errors should be generated. -TEST_F(VkLayerTest, TwoQueueSubmitsSeparateQueuesWithSemaphoreAndOneFenceTwoWFF) { - - TEST_DESCRIPTION("Two command buffers, each in a separate QueueSubmit call " - "submitted on separate queues, the second having a fence" - "followed by two consecutive WaitForFences calls on the same fence."); - - ASSERT_NO_FATAL_FAILURE(InitState()); - if ((m_device->queue_props.empty()) || (m_device->queue_props[0].queueCount < 2)) - return; - - m_errorMonitor->ExpectSuccess(); - - VkFence fence; - VkFenceCreateInfo fence_create_info{}; - fence_create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - vkCreateFence(m_device->device(), &fence_create_info, nullptr, &fence); - - VkSemaphore semaphore; - VkSemaphoreCreateInfo semaphore_create_info{}; - semaphore_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - vkCreateSemaphore(m_device->device(), &semaphore_create_info, nullptr, &semaphore); - - VkCommandPool command_pool; - VkCommandPoolCreateInfo pool_create_info{}; - pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_; - pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - vkCreateCommandPool(m_device->device(), &pool_create_info, nullptr, &command_pool); - - VkCommandBuffer command_buffer[2]; - VkCommandBufferAllocateInfo command_buffer_allocate_info{}; - command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - command_buffer_allocate_info.commandPool = command_pool; - command_buffer_allocate_info.commandBufferCount = 2; - command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - vkAllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, command_buffer); - - VkQueue queue = VK_NULL_HANDLE; - vkGetDeviceQueue(m_device->device(), m_device->graphics_queue_node_index_, 1, &queue); - - { - VkCommandBufferBeginInfo begin_info{}; - begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - vkBeginCommandBuffer(command_buffer[0], &begin_info); - - vkCmdPipelineBarrier(command_buffer[0], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, - nullptr, 0, nullptr, 0, nullptr); - - VkViewport viewport{}; - viewport.maxDepth = 1.0f; - viewport.minDepth = 0.0f; - viewport.width = 512; - viewport.height = 512; - viewport.x = 0; - viewport.y = 0; - vkCmdSetViewport(command_buffer[0], 0, 1, &viewport); - vkEndCommandBuffer(command_buffer[0]); - } - { - VkCommandBufferBeginInfo begin_info{}; - begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - vkBeginCommandBuffer(command_buffer[1], &begin_info); - - VkViewport viewport{}; - viewport.maxDepth = 1.0f; - viewport.minDepth = 0.0f; - viewport.width = 512; - viewport.height = 512; - viewport.x = 0; - viewport.y = 0; - vkCmdSetViewport(command_buffer[1], 0, 1, &viewport); - vkEndCommandBuffer(command_buffer[1]); - } - { - VkSubmitInfo submit_info{}; - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &command_buffer[0]; - submit_info.signalSemaphoreCount = 1; - submit_info.pSignalSemaphores = &semaphore; - vkQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE); - } - { - VkPipelineStageFlags flags[]{VK_PIPELINE_STAGE_ALL_COMMANDS_BIT}; - VkSubmitInfo submit_info{}; - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &command_buffer[1]; - submit_info.waitSemaphoreCount = 1; - submit_info.pWaitSemaphores = &semaphore; - submit_info.pWaitDstStageMask = flags; - vkQueueSubmit(m_device->m_queue, 1, &submit_info, fence); - } - - vkWaitForFences(m_device->device(), 1, &fence, VK_TRUE, UINT64_MAX); - vkWaitForFences(m_device->device(), 1, &fence, VK_TRUE, UINT64_MAX); - - vkDestroyFence(m_device->device(), fence, nullptr); - vkDestroySemaphore(m_device->device(), semaphore, nullptr); - vkFreeCommandBuffers(m_device->device(), command_pool, 2, &command_buffer[0]); - vkDestroyCommandPool(m_device->device(), command_pool, NULL); - - m_errorMonitor->VerifyNotFound(); -} - -TEST_F(VkLayerTest, TwoQueuesEnsureCorrectRetirementWithWorkStolen) { - - ASSERT_NO_FATAL_FAILURE(InitState()); - if ((m_device->queue_props.empty()) || (m_device->queue_props[0].queueCount < 2)) { - printf("Test requires two queues, skipping\n"); - return; - } - - VkResult err; - - m_errorMonitor->ExpectSuccess(); - - VkQueue q0 = m_device->m_queue; - VkQueue q1 = nullptr; - vkGetDeviceQueue(m_device->device(), m_device->graphics_queue_node_index_, 1, &q1); - ASSERT_NE(q1, nullptr); - - // An (empty) command buffer. We must have work in the first submission -- - // the layer treats unfenced work differently from fenced work. - VkCommandPoolCreateInfo cpci = {VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, nullptr, 0, 0}; - VkCommandPool pool; - err = vkCreateCommandPool(m_device->device(), &cpci, nullptr, &pool); - ASSERT_VK_SUCCESS(err); - VkCommandBufferAllocateInfo cbai = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, nullptr, pool, - VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1}; - VkCommandBuffer cb; - err = vkAllocateCommandBuffers(m_device->device(), &cbai, &cb); - ASSERT_VK_SUCCESS(err); - VkCommandBufferBeginInfo cbbi = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, nullptr, 0, nullptr}; - err = vkBeginCommandBuffer(cb, &cbbi); - ASSERT_VK_SUCCESS(err); - err = vkEndCommandBuffer(cb); - ASSERT_VK_SUCCESS(err); - - // A semaphore - VkSemaphoreCreateInfo sci = {VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, nullptr, 0}; - VkSemaphore s; - err = vkCreateSemaphore(m_device->device(), &sci, nullptr, &s); - ASSERT_VK_SUCCESS(err); - - // First submission, to q0 - VkSubmitInfo s0 = {VK_STRUCTURE_TYPE_SUBMIT_INFO, nullptr, 0, nullptr, nullptr, 1, &cb, 1, &s}; - - err = vkQueueSubmit(q0, 1, &s0, VK_NULL_HANDLE); - ASSERT_VK_SUCCESS(err); - - // Second submission, to q1, waiting on s - VkFlags waitmask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; // doesn't really matter what this value is. - VkSubmitInfo s1 = {VK_STRUCTURE_TYPE_SUBMIT_INFO, nullptr, 1, &s, &waitmask, 0, nullptr, 0, nullptr}; - - err = vkQueueSubmit(q1, 1, &s1, VK_NULL_HANDLE); - ASSERT_VK_SUCCESS(err); - - // Wait for q0 idle - err = vkQueueWaitIdle(q0); - ASSERT_VK_SUCCESS(err); - - // Command buffer should have been completed (it was on q0); reset the pool. - vkFreeCommandBuffers(m_device->device(), pool, 1, &cb); - - m_errorMonitor->VerifyNotFound(); - - // Force device completely idle and clean up resources - vkDeviceWaitIdle(m_device->device()); - vkDestroyCommandPool(m_device->device(), pool, nullptr); - vkDestroySemaphore(m_device->device(), s, nullptr); -} - -// This is a positive test. No errors should be generated. -TEST_F(VkLayerTest, TwoQueueSubmitsSeparateQueuesWithSemaphoreAndOneFence) { - - TEST_DESCRIPTION("Two command buffers, each in a separate QueueSubmit call " - "submitted on separate queues, the second having a fence, " - "followed by a WaitForFences call."); - - ASSERT_NO_FATAL_FAILURE(InitState()); - if ((m_device->queue_props.empty()) || (m_device->queue_props[0].queueCount < 2)) - return; - - m_errorMonitor->ExpectSuccess(); - - ASSERT_NO_FATAL_FAILURE(InitState()); - VkFence fence; - VkFenceCreateInfo fence_create_info{}; - fence_create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - vkCreateFence(m_device->device(), &fence_create_info, nullptr, &fence); - - VkSemaphore semaphore; - VkSemaphoreCreateInfo semaphore_create_info{}; - semaphore_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - vkCreateSemaphore(m_device->device(), &semaphore_create_info, nullptr, &semaphore); - - VkCommandPool command_pool; - VkCommandPoolCreateInfo pool_create_info{}; - pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_; - pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - vkCreateCommandPool(m_device->device(), &pool_create_info, nullptr, &command_pool); - - VkCommandBuffer command_buffer[2]; - VkCommandBufferAllocateInfo command_buffer_allocate_info{}; - command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - command_buffer_allocate_info.commandPool = command_pool; - command_buffer_allocate_info.commandBufferCount = 2; - command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - vkAllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, command_buffer); - - VkQueue queue = VK_NULL_HANDLE; - vkGetDeviceQueue(m_device->device(), m_device->graphics_queue_node_index_, 1, &queue); - - { - VkCommandBufferBeginInfo begin_info{}; - begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - vkBeginCommandBuffer(command_buffer[0], &begin_info); - - vkCmdPipelineBarrier(command_buffer[0], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, - nullptr, 0, nullptr, 0, nullptr); - - VkViewport viewport{}; - viewport.maxDepth = 1.0f; - viewport.minDepth = 0.0f; - viewport.width = 512; - viewport.height = 512; - viewport.x = 0; - viewport.y = 0; - vkCmdSetViewport(command_buffer[0], 0, 1, &viewport); - vkEndCommandBuffer(command_buffer[0]); - } - { - VkCommandBufferBeginInfo begin_info{}; - begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - vkBeginCommandBuffer(command_buffer[1], &begin_info); - - VkViewport viewport{}; - viewport.maxDepth = 1.0f; - viewport.minDepth = 0.0f; - viewport.width = 512; - viewport.height = 512; - viewport.x = 0; - viewport.y = 0; - vkCmdSetViewport(command_buffer[1], 0, 1, &viewport); - vkEndCommandBuffer(command_buffer[1]); - } - { - VkSubmitInfo submit_info{}; - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &command_buffer[0]; - submit_info.signalSemaphoreCount = 1; - submit_info.pSignalSemaphores = &semaphore; - vkQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE); - } - { - VkPipelineStageFlags flags[]{VK_PIPELINE_STAGE_ALL_COMMANDS_BIT}; - VkSubmitInfo submit_info{}; - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &command_buffer[1]; - submit_info.waitSemaphoreCount = 1; - submit_info.pWaitSemaphores = &semaphore; - submit_info.pWaitDstStageMask = flags; - vkQueueSubmit(m_device->m_queue, 1, &submit_info, fence); - } - - vkWaitForFences(m_device->device(), 1, &fence, VK_TRUE, UINT64_MAX); - - vkDestroyFence(m_device->device(), fence, nullptr); - vkDestroySemaphore(m_device->device(), semaphore, nullptr); - vkFreeCommandBuffers(m_device->device(), command_pool, 2, &command_buffer[0]); - vkDestroyCommandPool(m_device->device(), command_pool, NULL); - - m_errorMonitor->VerifyNotFound(); -} - -// This is a positive test. No errors should be generated. -TEST_F(VkLayerTest, TwoQueueSubmitsOneQueueWithSemaphoreAndOneFence) { - - TEST_DESCRIPTION("Two command buffers, each in a separate QueueSubmit call " - "on the same queue, sharing a signal/wait semaphore, the " - "second having a fence, " - "followed by a WaitForFences call."); - - m_errorMonitor->ExpectSuccess(); - - ASSERT_NO_FATAL_FAILURE(InitState()); - VkFence fence; - VkFenceCreateInfo fence_create_info{}; - fence_create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - vkCreateFence(m_device->device(), &fence_create_info, nullptr, &fence); - - VkSemaphore semaphore; - VkSemaphoreCreateInfo semaphore_create_info{}; - semaphore_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - vkCreateSemaphore(m_device->device(), &semaphore_create_info, nullptr, &semaphore); - - VkCommandPool command_pool; - VkCommandPoolCreateInfo pool_create_info{}; - pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_; - pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - vkCreateCommandPool(m_device->device(), &pool_create_info, nullptr, &command_pool); - - VkCommandBuffer command_buffer[2]; - VkCommandBufferAllocateInfo command_buffer_allocate_info{}; - command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - command_buffer_allocate_info.commandPool = command_pool; - command_buffer_allocate_info.commandBufferCount = 2; - command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - vkAllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, command_buffer); - - { - VkCommandBufferBeginInfo begin_info{}; - begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - vkBeginCommandBuffer(command_buffer[0], &begin_info); - - vkCmdPipelineBarrier(command_buffer[0], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, - nullptr, 0, nullptr, 0, nullptr); - - VkViewport viewport{}; - viewport.maxDepth = 1.0f; - viewport.minDepth = 0.0f; - viewport.width = 512; - viewport.height = 512; - viewport.x = 0; - viewport.y = 0; - vkCmdSetViewport(command_buffer[0], 0, 1, &viewport); - vkEndCommandBuffer(command_buffer[0]); - } - { - VkCommandBufferBeginInfo begin_info{}; - begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - vkBeginCommandBuffer(command_buffer[1], &begin_info); - - VkViewport viewport{}; - viewport.maxDepth = 1.0f; - viewport.minDepth = 0.0f; - viewport.width = 512; - viewport.height = 512; - viewport.x = 0; - viewport.y = 0; - vkCmdSetViewport(command_buffer[1], 0, 1, &viewport); - vkEndCommandBuffer(command_buffer[1]); - } - { - VkSubmitInfo submit_info{}; - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &command_buffer[0]; - submit_info.signalSemaphoreCount = 1; - submit_info.pSignalSemaphores = &semaphore; - vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); - } - { - VkPipelineStageFlags flags[]{VK_PIPELINE_STAGE_ALL_COMMANDS_BIT}; - VkSubmitInfo submit_info{}; - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &command_buffer[1]; - submit_info.waitSemaphoreCount = 1; - submit_info.pWaitSemaphores = &semaphore; - submit_info.pWaitDstStageMask = flags; - vkQueueSubmit(m_device->m_queue, 1, &submit_info, fence); - } - - vkWaitForFences(m_device->device(), 1, &fence, VK_TRUE, UINT64_MAX); - - vkDestroyFence(m_device->device(), fence, nullptr); - vkDestroySemaphore(m_device->device(), semaphore, nullptr); - vkFreeCommandBuffers(m_device->device(), command_pool, 2, &command_buffer[0]); - vkDestroyCommandPool(m_device->device(), command_pool, NULL); - - m_errorMonitor->VerifyNotFound(); -} - -// This is a positive test. No errors should be generated. -TEST_F(VkLayerTest, TwoQueueSubmitsOneQueueNullQueueSubmitWithFence) { - - TEST_DESCRIPTION("Two command buffers, each in a separate QueueSubmit call " - "on the same queue, no fences, followed by a third QueueSubmit with NO " - "SubmitInfos but with a fence, followed by a WaitForFences call."); - - m_errorMonitor->ExpectSuccess(); - - ASSERT_NO_FATAL_FAILURE(InitState()); - VkFence fence; - VkFenceCreateInfo fence_create_info{}; - fence_create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - vkCreateFence(m_device->device(), &fence_create_info, nullptr, &fence); - - VkCommandPool command_pool; - VkCommandPoolCreateInfo pool_create_info{}; - pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_; - pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - vkCreateCommandPool(m_device->device(), &pool_create_info, nullptr, &command_pool); - - VkCommandBuffer command_buffer[2]; - VkCommandBufferAllocateInfo command_buffer_allocate_info{}; - command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - command_buffer_allocate_info.commandPool = command_pool; - command_buffer_allocate_info.commandBufferCount = 2; - command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - vkAllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, command_buffer); - - { - VkCommandBufferBeginInfo begin_info{}; - begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - vkBeginCommandBuffer(command_buffer[0], &begin_info); - - vkCmdPipelineBarrier(command_buffer[0], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, - nullptr, 0, nullptr, 0, nullptr); - - VkViewport viewport{}; - viewport.maxDepth = 1.0f; - viewport.minDepth = 0.0f; - viewport.width = 512; - viewport.height = 512; - viewport.x = 0; - viewport.y = 0; - vkCmdSetViewport(command_buffer[0], 0, 1, &viewport); - vkEndCommandBuffer(command_buffer[0]); - } - { - VkCommandBufferBeginInfo begin_info{}; - begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - vkBeginCommandBuffer(command_buffer[1], &begin_info); - - VkViewport viewport{}; - viewport.maxDepth = 1.0f; - viewport.minDepth = 0.0f; - viewport.width = 512; - viewport.height = 512; - viewport.x = 0; - viewport.y = 0; - vkCmdSetViewport(command_buffer[1], 0, 1, &viewport); - vkEndCommandBuffer(command_buffer[1]); - } - { - VkSubmitInfo submit_info{}; - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &command_buffer[0]; - submit_info.signalSemaphoreCount = 0; - submit_info.pSignalSemaphores = VK_NULL_HANDLE; - vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); - } - { - VkPipelineStageFlags flags[]{VK_PIPELINE_STAGE_ALL_COMMANDS_BIT}; - VkSubmitInfo submit_info{}; - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &command_buffer[1]; - submit_info.waitSemaphoreCount = 0; - submit_info.pWaitSemaphores = VK_NULL_HANDLE; - submit_info.pWaitDstStageMask = flags; - vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); - } - - vkQueueSubmit(m_device->m_queue, 0, NULL, fence); - - VkResult err = vkWaitForFences(m_device->device(), 1, &fence, VK_TRUE, UINT64_MAX); - ASSERT_VK_SUCCESS(err); - - vkDestroyFence(m_device->device(), fence, nullptr); - vkFreeCommandBuffers(m_device->device(), command_pool, 2, &command_buffer[0]); - vkDestroyCommandPool(m_device->device(), command_pool, NULL); - - m_errorMonitor->VerifyNotFound(); -} - -// This is a positive test. No errors should be generated. -TEST_F(VkLayerTest, TwoQueueSubmitsOneQueueOneFence) { - - TEST_DESCRIPTION("Two command buffers, each in a separate QueueSubmit call " - "on the same queue, the second having a fence, followed " - "by a WaitForFences call."); - - m_errorMonitor->ExpectSuccess(); - - ASSERT_NO_FATAL_FAILURE(InitState()); - VkFence fence; - VkFenceCreateInfo fence_create_info{}; - fence_create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - vkCreateFence(m_device->device(), &fence_create_info, nullptr, &fence); - - VkCommandPool command_pool; - VkCommandPoolCreateInfo pool_create_info{}; - pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_; - pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - vkCreateCommandPool(m_device->device(), &pool_create_info, nullptr, &command_pool); - - VkCommandBuffer command_buffer[2]; - VkCommandBufferAllocateInfo command_buffer_allocate_info{}; - command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - command_buffer_allocate_info.commandPool = command_pool; - command_buffer_allocate_info.commandBufferCount = 2; - command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - vkAllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, command_buffer); - - { - VkCommandBufferBeginInfo begin_info{}; - begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - vkBeginCommandBuffer(command_buffer[0], &begin_info); - - vkCmdPipelineBarrier(command_buffer[0], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, - nullptr, 0, nullptr, 0, nullptr); - - VkViewport viewport{}; - viewport.maxDepth = 1.0f; - viewport.minDepth = 0.0f; - viewport.width = 512; - viewport.height = 512; - viewport.x = 0; - viewport.y = 0; - vkCmdSetViewport(command_buffer[0], 0, 1, &viewport); - vkEndCommandBuffer(command_buffer[0]); - } - { - VkCommandBufferBeginInfo begin_info{}; - begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - vkBeginCommandBuffer(command_buffer[1], &begin_info); - - VkViewport viewport{}; - viewport.maxDepth = 1.0f; - viewport.minDepth = 0.0f; - viewport.width = 512; - viewport.height = 512; - viewport.x = 0; - viewport.y = 0; - vkCmdSetViewport(command_buffer[1], 0, 1, &viewport); - vkEndCommandBuffer(command_buffer[1]); - } - { - VkSubmitInfo submit_info{}; - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &command_buffer[0]; - submit_info.signalSemaphoreCount = 0; - submit_info.pSignalSemaphores = VK_NULL_HANDLE; - vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); - } - { - VkPipelineStageFlags flags[]{VK_PIPELINE_STAGE_ALL_COMMANDS_BIT}; - VkSubmitInfo submit_info{}; - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &command_buffer[1]; - submit_info.waitSemaphoreCount = 0; - submit_info.pWaitSemaphores = VK_NULL_HANDLE; - submit_info.pWaitDstStageMask = flags; - vkQueueSubmit(m_device->m_queue, 1, &submit_info, fence); - } - - vkWaitForFences(m_device->device(), 1, &fence, VK_TRUE, UINT64_MAX); - - vkDestroyFence(m_device->device(), fence, nullptr); - vkFreeCommandBuffers(m_device->device(), command_pool, 2, &command_buffer[0]); - vkDestroyCommandPool(m_device->device(), command_pool, NULL); - - m_errorMonitor->VerifyNotFound(); -} - -// This is a positive test. No errors should be generated. -TEST_F(VkLayerTest, TwoSubmitInfosWithSemaphoreOneQueueSubmitsOneFence) { - - TEST_DESCRIPTION("Two command buffers each in a separate SubmitInfo sent in a single " - "QueueSubmit call followed by a WaitForFences call."); - ASSERT_NO_FATAL_FAILURE(InitState()); - - m_errorMonitor->ExpectSuccess(); - - VkFence fence; - VkFenceCreateInfo fence_create_info{}; - fence_create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - vkCreateFence(m_device->device(), &fence_create_info, nullptr, &fence); - - VkSemaphore semaphore; - VkSemaphoreCreateInfo semaphore_create_info{}; - semaphore_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - vkCreateSemaphore(m_device->device(), &semaphore_create_info, nullptr, &semaphore); - - VkCommandPool command_pool; - VkCommandPoolCreateInfo pool_create_info{}; - pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_; - pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - vkCreateCommandPool(m_device->device(), &pool_create_info, nullptr, &command_pool); - - VkCommandBuffer command_buffer[2]; - VkCommandBufferAllocateInfo command_buffer_allocate_info{}; - command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - command_buffer_allocate_info.commandPool = command_pool; - command_buffer_allocate_info.commandBufferCount = 2; - command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - vkAllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, command_buffer); - - { - VkCommandBufferBeginInfo begin_info{}; - begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - vkBeginCommandBuffer(command_buffer[0], &begin_info); - - vkCmdPipelineBarrier(command_buffer[0], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, - nullptr, 0, nullptr, 0, nullptr); - - VkViewport viewport{}; - viewport.maxDepth = 1.0f; - viewport.minDepth = 0.0f; - viewport.width = 512; - viewport.height = 512; - viewport.x = 0; - viewport.y = 0; - vkCmdSetViewport(command_buffer[0], 0, 1, &viewport); - vkEndCommandBuffer(command_buffer[0]); - } - { - VkCommandBufferBeginInfo begin_info{}; - begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - vkBeginCommandBuffer(command_buffer[1], &begin_info); - - VkViewport viewport{}; - viewport.maxDepth = 1.0f; - viewport.minDepth = 0.0f; - viewport.width = 512; - viewport.height = 512; - viewport.x = 0; - viewport.y = 0; - vkCmdSetViewport(command_buffer[1], 0, 1, &viewport); - vkEndCommandBuffer(command_buffer[1]); - } - { - VkSubmitInfo submit_info[2]; - VkPipelineStageFlags flags[]{VK_PIPELINE_STAGE_ALL_COMMANDS_BIT}; - - submit_info[0].sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info[0].pNext = NULL; - submit_info[0].commandBufferCount = 1; - submit_info[0].pCommandBuffers = &command_buffer[0]; - submit_info[0].signalSemaphoreCount = 1; - submit_info[0].pSignalSemaphores = &semaphore; - submit_info[0].waitSemaphoreCount = 0; - submit_info[0].pWaitSemaphores = NULL; - submit_info[0].pWaitDstStageMask = 0; - - submit_info[1].sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info[1].pNext = NULL; - submit_info[1].commandBufferCount = 1; - submit_info[1].pCommandBuffers = &command_buffer[1]; - submit_info[1].waitSemaphoreCount = 1; - submit_info[1].pWaitSemaphores = &semaphore; - submit_info[1].pWaitDstStageMask = flags; - submit_info[1].signalSemaphoreCount = 0; - submit_info[1].pSignalSemaphores = NULL; - vkQueueSubmit(m_device->m_queue, 2, &submit_info[0], fence); - } - - vkWaitForFences(m_device->device(), 1, &fence, VK_TRUE, UINT64_MAX); - - vkDestroyFence(m_device->device(), fence, nullptr); - vkFreeCommandBuffers(m_device->device(), command_pool, 2, &command_buffer[0]); - vkDestroyCommandPool(m_device->device(), command_pool, NULL); - vkDestroySemaphore(m_device->device(), semaphore, nullptr); - - m_errorMonitor->VerifyNotFound(); -} - TEST_F(VkLayerTest, DynamicDepthBiasNotBound) { TEST_DESCRIPTION("Run a simple draw calls to validate failure when Depth Bias dynamic " "state is required but not correctly bound."); @@ -6877,7 +3636,7 @@ TEST_F(VkLayerTest, InvalidDescriptorPool) { m_errorMonitor->VerifyFound(); } -TEST_F(VkLayerTest, InvalidDescriptorSet) { +TEST_F(VkPositiveLayerTest, InvalidDescriptorSet) { // Attempt to bind an invalid Descriptor Set to a valid Command Buffer // ObjectTracker should catch this. // Create a valid cmd buffer @@ -9201,29 +5960,6 @@ TEST_F(VkLayerTest, InvalidPushConstants) { } } - // Run some positive tests to make sure overlap checking in the layer is OK - const std::array<OverlappingRangeTestCase, 2> overlapping_range_tests_pos = {{{{{VK_SHADER_STAGE_VERTEX_BIT, 0, 4}, - {VK_SHADER_STAGE_VERTEX_BIT, 4, 4}, - {VK_SHADER_STAGE_VERTEX_BIT, 8, 4}, - {VK_SHADER_STAGE_VERTEX_BIT, 12, 4}, - {VK_SHADER_STAGE_VERTEX_BIT, 16, 4}}, - ""}, - {{{VK_SHADER_STAGE_VERTEX_BIT, 92, 24}, - {VK_SHADER_STAGE_VERTEX_BIT, 80, 4}, - {VK_SHADER_STAGE_VERTEX_BIT, 64, 8}, - {VK_SHADER_STAGE_VERTEX_BIT, 4, 16}, - {VK_SHADER_STAGE_VERTEX_BIT, 0, 4}}, - ""}}}; - for (const auto &iter : overlapping_range_tests_pos) { - pipeline_layout_ci.pPushConstantRanges = iter.ranges; - m_errorMonitor->ExpectSuccess(); - err = vkCreatePipelineLayout(m_device->device(), &pipeline_layout_ci, NULL, &pipeline_layout); - m_errorMonitor->VerifyNotFound(); - if (VK_SUCCESS == err) { - vkDestroyPipelineLayout(m_device->device(), pipeline_layout, NULL); - } - } - // // CmdPushConstants tests // @@ -9316,30 +6052,6 @@ TEST_F(VkLayerTest, InvalidPushConstants) { } vkDestroyPipelineLayout(m_device->device(), pipeline_layout, NULL); - // positive overlapping range tests with cmd - const std::array<PipelineLayoutTestCase, 4> cmd_overlap_tests_pos = {{ - {{VK_SHADER_STAGE_VERTEX_BIT, 0, 16}, ""}, - {{VK_SHADER_STAGE_VERTEX_BIT, 0, 4}, ""}, - {{VK_SHADER_STAGE_VERTEX_BIT, 20, 12}, ""}, - {{VK_SHADER_STAGE_VERTEX_BIT, 56, 36}, ""}, - }}; - // Setup ranges: [0,16) [20,36) [36,44) [44,52) [56,80) [80,92) - const VkPushConstantRange pc_range4[] = { - {VK_SHADER_STAGE_VERTEX_BIT, 20, 16}, {VK_SHADER_STAGE_VERTEX_BIT, 0, 16}, {VK_SHADER_STAGE_VERTEX_BIT, 44, 8}, - {VK_SHADER_STAGE_VERTEX_BIT, 80, 12}, {VK_SHADER_STAGE_VERTEX_BIT, 36, 8}, {VK_SHADER_STAGE_VERTEX_BIT, 56, 24}, - }; - pipeline_layout_ci.pushConstantRangeCount = sizeof(pc_range4) / sizeof(VkPushConstantRange); - pipeline_layout_ci.pPushConstantRanges = pc_range4; - err = vkCreatePipelineLayout(m_device->device(), &pipeline_layout_ci, NULL, &pipeline_layout); - ASSERT_VK_SUCCESS(err); - for (const auto &iter : cmd_overlap_tests_pos) { - m_errorMonitor->ExpectSuccess(); - vkCmdPushConstants(m_commandBuffer->GetBufferHandle(), pipeline_layout, iter.range.stageFlags, iter.range.offset, - iter.range.size, dummy_values); - m_errorMonitor->VerifyNotFound(); - } - vkDestroyPipelineLayout(m_device->device(), pipeline_layout, NULL); - EndCommandBuffer(); } @@ -10825,27 +7537,6 @@ TEST_F(VkLayerTest, RenderPassWithinRenderPass) { m_errorMonitor->VerifyFound(); } -TEST_F(VkLayerTest, RenderPassSecondaryCommandBuffersMultipleTimes) { - m_errorMonitor->ExpectSuccess(); - - ASSERT_NO_FATAL_FAILURE(InitState()); - ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); - - BeginCommandBuffer(); // framework implicitly begins the renderpass. - vkCmdEndRenderPass(m_commandBuffer->GetBufferHandle()); // end implicit. - - vkCmdBeginRenderPass(m_commandBuffer->GetBufferHandle(), &m_renderPassBeginInfo, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); - vkCmdEndRenderPass(m_commandBuffer->GetBufferHandle()); - m_errorMonitor->VerifyNotFound(); - vkCmdBeginRenderPass(m_commandBuffer->GetBufferHandle(), &m_renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - m_errorMonitor->VerifyNotFound(); - vkCmdEndRenderPass(m_commandBuffer->GetBufferHandle()); - m_errorMonitor->VerifyNotFound(); - - m_commandBuffer->EndCommandBuffer(); - m_errorMonitor->VerifyNotFound(); -} - TEST_F(VkLayerTest, RenderPassClearOpMismatch) { TEST_DESCRIPTION("Begin a renderPass where clearValueCount is less than" "the number of renderPass attachments that use loadOp" @@ -11415,7 +8106,7 @@ TEST_F(VkLayerTest, InvalidQueueFamilyIndex) { } TEST_F(VkLayerTest, ExecuteCommandsPrimaryCB) { - TEST_DESCRIPTION("Attempt vkCmdExecuteCommands with a primary command buffer" +TEST_DESCRIPTION("Attempt vkCmdExecuteCommands with a primary command buffer" " (should only be secondary)"); ASSERT_NO_FATAL_FAILURE(InitState()); @@ -13568,49 +10259,6 @@ TEST_F(VkLayerTest, InvalidStorageImageLayout) { vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL); } -TEST_F(VkLayerTest, ValidRenderPassAttachmentLayoutWithLoadOp) { - TEST_DESCRIPTION("Positive test where we create a renderpass with an " - "attachment that uses LOAD_OP_CLEAR, the first subpass " - "has a valid layout, and a second subpass then uses a " - "valid *READ_ONLY* layout."); - m_errorMonitor->ExpectSuccess(); - ASSERT_NO_FATAL_FAILURE(InitState()); - - VkAttachmentReference attach[2] = {}; - attach[0].attachment = 0; - attach[0].layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - attach[1].attachment = 0; - attach[1].layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; - VkSubpassDescription subpasses[2] = {}; - // First subpass clears DS attach on load - subpasses[0].pDepthStencilAttachment = &attach[0]; - // 2nd subpass reads in DS as input attachment - subpasses[1].inputAttachmentCount = 1; - subpasses[1].pInputAttachments = &attach[1]; - VkAttachmentDescription attach_desc = {}; - attach_desc.format = VK_FORMAT_D24_UNORM_S8_UINT; - attach_desc.samples = VK_SAMPLE_COUNT_1_BIT; - attach_desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attach_desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attach_desc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attach_desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attach_desc.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - attach_desc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; - VkRenderPassCreateInfo rpci = {}; - rpci.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - rpci.attachmentCount = 1; - rpci.pAttachments = &attach_desc; - rpci.subpassCount = 2; - rpci.pSubpasses = subpasses; - - // Now create RenderPass and verify no errors - VkRenderPass rp; - vkCreateRenderPass(m_device->device(), &rpci, NULL, &rp); - m_errorMonitor->VerifyNotFound(); - - vkDestroyRenderPass(m_device->device(), rp, NULL); -} - TEST_F(VkLayerTest, SimultaneousUse) { TEST_DESCRIPTION("Use vkCmdExecuteCommands with invalid state " "in primary and secondary command buffers."); @@ -15443,6 +12091,7 @@ TEST_F(VkLayerTest, CreatePipelineVsFsTypeMismatchArraySize) { m_errorMonitor->VerifyFound(); } + TEST_F(VkLayerTest, CreatePipelineVsFsTypeMismatch) { TEST_DESCRIPTION("Test that an error is produced for mismatched types across " "the vertex->fragment shader interface"); @@ -15854,174 +12503,6 @@ TEST_F(VkLayerTest, CreatePipelineDuplicateStage) { m_errorMonitor->VerifyFound(); } -TEST_F(VkLayerTest, CreatePipelineAttribMatrixType) { - TEST_DESCRIPTION("Test that pipeline validation accepts matrices passed " - "as vertex attributes"); - m_errorMonitor->ExpectSuccess(); - - ASSERT_NO_FATAL_FAILURE(InitState()); - ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); - - VkVertexInputBindingDescription input_binding; - memset(&input_binding, 0, sizeof(input_binding)); - - VkVertexInputAttributeDescription input_attribs[2]; - memset(input_attribs, 0, sizeof(input_attribs)); - - for (int i = 0; i < 2; i++) { - input_attribs[i].format = VK_FORMAT_R32G32B32A32_SFLOAT; - input_attribs[i].location = i; - } - - char const *vsSource = "#version 450\n" - "\n" - "layout(location=0) in mat2x4 x;\n" - "out gl_PerVertex {\n" - " vec4 gl_Position;\n" - "};\n" - "void main(){\n" - " gl_Position = x[0] + x[1];\n" - "}\n"; - char const *fsSource = "#version 450\n" - "\n" - "layout(location=0) out vec4 color;\n" - "void main(){\n" - " color = vec4(1);\n" - "}\n"; - - VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); - VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); - - VkPipelineObj pipe(m_device); - pipe.AddColorAttachment(); - pipe.AddShader(&vs); - pipe.AddShader(&fs); - - pipe.AddVertexInputBindings(&input_binding, 1); - pipe.AddVertexInputAttribs(input_attribs, 2); - - VkDescriptorSetObj descriptorSet(m_device); - descriptorSet.AppendDummy(); - descriptorSet.CreateVKDescriptorSet(m_commandBuffer); - - pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); - - /* expect success */ - m_errorMonitor->VerifyNotFound(); -} - -TEST_F(VkLayerTest, CreatePipelineAttribArrayType) { - m_errorMonitor->ExpectSuccess(); - - ASSERT_NO_FATAL_FAILURE(InitState()); - ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); - - VkVertexInputBindingDescription input_binding; - memset(&input_binding, 0, sizeof(input_binding)); - - VkVertexInputAttributeDescription input_attribs[2]; - memset(input_attribs, 0, sizeof(input_attribs)); - - for (int i = 0; i < 2; i++) { - input_attribs[i].format = VK_FORMAT_R32G32B32A32_SFLOAT; - input_attribs[i].location = i; - } - - char const *vsSource = "#version 450\n" - "\n" - "layout(location=0) in vec4 x[2];\n" - "out gl_PerVertex {\n" - " vec4 gl_Position;\n" - "};\n" - "void main(){\n" - " gl_Position = x[0] + x[1];\n" - "}\n"; - char const *fsSource = "#version 450\n" - "\n" - "layout(location=0) out vec4 color;\n" - "void main(){\n" - " color = vec4(1);\n" - "}\n"; - - VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); - VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); - - VkPipelineObj pipe(m_device); - pipe.AddColorAttachment(); - pipe.AddShader(&vs); - pipe.AddShader(&fs); - - pipe.AddVertexInputBindings(&input_binding, 1); - pipe.AddVertexInputAttribs(input_attribs, 2); - - VkDescriptorSetObj descriptorSet(m_device); - descriptorSet.AppendDummy(); - descriptorSet.CreateVKDescriptorSet(m_commandBuffer); - - pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); - - m_errorMonitor->VerifyNotFound(); -} - -TEST_F(VkLayerTest, CreatePipelineAttribComponents) { - TEST_DESCRIPTION("Test that pipeline validation accepts consuming a vertex attribute " - "through multiple vertex shader inputs, each consuming a different " - "subset of the components."); - m_errorMonitor->ExpectSuccess(); - - ASSERT_NO_FATAL_FAILURE(InitState()); - ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); - - VkVertexInputBindingDescription input_binding; - memset(&input_binding, 0, sizeof(input_binding)); - - VkVertexInputAttributeDescription input_attribs[3]; - memset(input_attribs, 0, sizeof(input_attribs)); - - for (int i = 0; i < 3; i++) { - input_attribs[i].format = VK_FORMAT_R32G32B32A32_SFLOAT; - input_attribs[i].location = i; - } - - char const *vsSource = "#version 450\n" - "\n" - "layout(location=0) in vec4 x;\n" - "layout(location=1) in vec3 y1;\n" - "layout(location=1, component=3) in float y2;\n" - "layout(location=2) in vec4 z;\n" - "out gl_PerVertex {\n" - " vec4 gl_Position;\n" - "};\n" - "void main(){\n" - " gl_Position = x + vec4(y1, y2) + z;\n" - "}\n"; - char const *fsSource = "#version 450\n" - "\n" - "layout(location=0) out vec4 color;\n" - "void main(){\n" - " color = vec4(1);\n" - "}\n"; - - VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); - VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); - - VkPipelineObj pipe(m_device); - pipe.AddColorAttachment(); - pipe.AddShader(&vs); - pipe.AddShader(&fs); - - pipe.AddVertexInputBindings(&input_binding, 1); - pipe.AddVertexInputAttribs(input_attribs, 3); - - VkDescriptorSetObj descriptorSet(m_device); - descriptorSet.AppendDummy(); - descriptorSet.CreateVKDescriptorSet(m_commandBuffer); - - pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); - - m_errorMonitor->VerifyNotFound(); -} - TEST_F(VkLayerTest, CreatePipelineMissingEntrypoint) { m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "No entrypoint found named `foo`"); @@ -16060,43 +12541,6 @@ TEST_F(VkLayerTest, CreatePipelineMissingEntrypoint) { m_errorMonitor->VerifyFound(); } -TEST_F(VkLayerTest, CreatePipelineSimplePositive) { - m_errorMonitor->ExpectSuccess(); - - ASSERT_NO_FATAL_FAILURE(InitState()); - ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); - - char const *vsSource = "#version 450\n" - "out gl_PerVertex {\n" - " vec4 gl_Position;\n" - "};\n" - "void main(){\n" - " gl_Position = vec4(0);\n" - "}\n"; - char const *fsSource = "#version 450\n" - "\n" - "layout(location=0) out vec4 color;\n" - "void main(){\n" - " color = vec4(1);\n" - "}\n"; - - VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); - VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); - - VkPipelineObj pipe(m_device); - pipe.AddColorAttachment(); - pipe.AddShader(&vs); - pipe.AddShader(&fs); - - VkDescriptorSetObj descriptorSet(m_device); - descriptorSet.AppendDummy(); - descriptorSet.CreateVKDescriptorSet(m_commandBuffer); - - pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); - - m_errorMonitor->VerifyNotFound(); -} - TEST_F(VkLayerTest, CreatePipelineDepthStencilRequired) { m_errorMonitor->SetDesiredFailureMsg( VK_DEBUG_REPORT_ERROR_BIT_EXT, @@ -16163,176 +12607,6 @@ TEST_F(VkLayerTest, CreatePipelineDepthStencilRequired) { vkDestroyRenderPass(m_device->device(), rp, nullptr); } -TEST_F(VkLayerTest, CreatePipelineRelaxedTypeMatch) { - TEST_DESCRIPTION("Test that pipeline validation accepts the relaxed type matching rules " - "set out in 14.1.3: fundamental type must match, and producer side must " - "have at least as many components"); - m_errorMonitor->ExpectSuccess(); - - // VK 1.0.8 Specification, 14.1.3 "Additionally,..." block - - ASSERT_NO_FATAL_FAILURE(InitState()); - ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); - - char const *vsSource = "#version 450\n" - "out gl_PerVertex {\n" - " vec4 gl_Position;\n" - "};\n" - "layout(location=0) out vec3 x;\n" - "layout(location=1) out ivec3 y;\n" - "layout(location=2) out vec3 z;\n" - "void main(){\n" - " gl_Position = vec4(0);\n" - " x = vec3(0); y = ivec3(0); z = vec3(0);\n" - "}\n"; - char const *fsSource = "#version 450\n" - "\n" - "layout(location=0) out vec4 color;\n" - "layout(location=0) in float x;\n" - "layout(location=1) flat in int y;\n" - "layout(location=2) in vec2 z;\n" - "void main(){\n" - " color = vec4(1 + x + y + z.x);\n" - "}\n"; - - VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); - VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); - - VkPipelineObj pipe(m_device); - pipe.AddColorAttachment(); - pipe.AddShader(&vs); - pipe.AddShader(&fs); - - VkDescriptorSetObj descriptorSet(m_device); - descriptorSet.AppendDummy(); - descriptorSet.CreateVKDescriptorSet(m_commandBuffer); - - VkResult err = VK_SUCCESS; - err = pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); - ASSERT_VK_SUCCESS(err); - - m_errorMonitor->VerifyNotFound(); -} - -TEST_F(VkLayerTest, CreatePipelineTessPerVertex) { - TEST_DESCRIPTION("Test that pipeline validation accepts per-vertex variables " - "passed between the TCS and TES stages"); - m_errorMonitor->ExpectSuccess(); - - ASSERT_NO_FATAL_FAILURE(InitState()); - ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); - - if (!m_device->phy().features().tessellationShader) { - printf("Device does not support tessellation shaders; skipped.\n"); - return; - } - - char const *vsSource = "#version 450\n" - "void main(){}\n"; - char const *tcsSource = "#version 450\n" - "layout(location=0) out int x[];\n" - "layout(vertices=3) out;\n" - "void main(){\n" - " gl_TessLevelOuter[0] = gl_TessLevelOuter[1] = gl_TessLevelOuter[2] = 1;\n" - " gl_TessLevelInner[0] = 1;\n" - " x[gl_InvocationID] = gl_InvocationID;\n" - "}\n"; - char const *tesSource = "#version 450\n" - "layout(triangles, equal_spacing, cw) in;\n" - "layout(location=0) in int x[];\n" - "out gl_PerVertex { vec4 gl_Position; };\n" - "void main(){\n" - " gl_Position.xyz = gl_TessCoord;\n" - " gl_Position.w = x[0] + x[1] + x[2];\n" - "}\n"; - char const *fsSource = "#version 450\n" - "layout(location=0) out vec4 color;\n" - "void main(){\n" - " color = vec4(1);\n" - "}\n"; - - VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); - VkShaderObj tcs(m_device, tcsSource, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, this); - VkShaderObj tes(m_device, tesSource, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, this); - VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); - - VkPipelineInputAssemblyStateCreateInfo iasci{VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, nullptr, 0, - VK_PRIMITIVE_TOPOLOGY_PATCH_LIST, VK_FALSE}; - - VkPipelineTessellationStateCreateInfo tsci{VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO, nullptr, 0, 3}; - - VkPipelineObj pipe(m_device); - pipe.SetInputAssembly(&iasci); - pipe.SetTessellation(&tsci); - pipe.AddColorAttachment(); - pipe.AddShader(&vs); - pipe.AddShader(&tcs); - pipe.AddShader(&tes); - pipe.AddShader(&fs); - - VkDescriptorSetObj descriptorSet(m_device); - descriptorSet.AppendDummy(); - descriptorSet.CreateVKDescriptorSet(m_commandBuffer); - - pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); - - m_errorMonitor->VerifyNotFound(); -} - -TEST_F(VkLayerTest, CreatePipelineGeometryInputBlockPositive) { - TEST_DESCRIPTION("Test that pipeline validation accepts a user-defined " - "interface block passed into the geometry shader. This " - "is interesting because the 'extra' array level is not " - "present on the member type, but on the block instance."); - m_errorMonitor->ExpectSuccess(); - - ASSERT_NO_FATAL_FAILURE(InitState()); - ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); - - if (!m_device->phy().features().geometryShader) { - printf("Device does not support geometry shaders; skipped.\n"); - return; - } - - char const *vsSource = "#version 450\n" - "layout(location=0) out VertexData { vec4 x; } vs_out;\n" - "void main(){\n" - " vs_out.x = vec4(1);\n" - "}\n"; - char const *gsSource = "#version 450\n" - "layout(triangles) in;\n" - "layout(triangle_strip, max_vertices=3) out;\n" - "layout(location=0) in VertexData { vec4 x; } gs_in[];\n" - "out gl_PerVertex { vec4 gl_Position; };\n" - "void main() {\n" - " gl_Position = gs_in[0].x;\n" - " EmitVertex();\n" - "}\n"; - char const *fsSource = "#version 450\n" - "layout(location=0) out vec4 color;\n" - "void main(){\n" - " color = vec4(1);\n" - "}\n"; - - VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); - VkShaderObj gs(m_device, gsSource, VK_SHADER_STAGE_GEOMETRY_BIT, this); - VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); - - VkPipelineObj pipe(m_device); - pipe.AddColorAttachment(); - pipe.AddShader(&vs); - pipe.AddShader(&gs); - pipe.AddShader(&fs); - - VkDescriptorSetObj descriptorSet(m_device); - descriptorSet.AppendDummy(); - descriptorSet.CreateVKDescriptorSet(m_commandBuffer); - - pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); - - m_errorMonitor->VerifyNotFound(); -} - TEST_F(VkLayerTest, CreatePipelineTessPatchDecorationMismatch) { TEST_DESCRIPTION("Test that an error is produced for a variable output from " "the TCS without the patch decoration, but consumed in the TES " @@ -16453,74 +12727,6 @@ TEST_F(VkLayerTest, CreatePipelineAttribBindingConflict) { m_errorMonitor->VerifyFound(); } -TEST_F(VkLayerTest, CreatePipeline64BitAttributesPositive) { - TEST_DESCRIPTION("Test that pipeline validation accepts basic use of 64bit vertex " - "attributes. This is interesting because they consume multiple " - "locations."); - m_errorMonitor->ExpectSuccess(); - - ASSERT_NO_FATAL_FAILURE(InitState()); - ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); - - if (!m_device->phy().features().shaderFloat64) { - printf("Device does not support 64bit vertex attributes; skipped.\n"); - return; - } - - VkVertexInputBindingDescription input_bindings[1]; - memset(input_bindings, 0, sizeof(input_bindings)); - - VkVertexInputAttributeDescription input_attribs[4]; - memset(input_attribs, 0, sizeof(input_attribs)); - input_attribs[0].location = 0; - input_attribs[0].offset = 0; - input_attribs[0].format = VK_FORMAT_R64G64B64A64_SFLOAT; - input_attribs[1].location = 2; - input_attribs[1].offset = 32; - input_attribs[1].format = VK_FORMAT_R64G64B64A64_SFLOAT; - input_attribs[2].location = 4; - input_attribs[2].offset = 64; - input_attribs[2].format = VK_FORMAT_R64G64B64A64_SFLOAT; - input_attribs[3].location = 6; - input_attribs[3].offset = 96; - input_attribs[3].format = VK_FORMAT_R64G64B64A64_SFLOAT; - - char const *vsSource = "#version 450\n" - "\n" - "layout(location=0) in dmat4 x;\n" - "out gl_PerVertex {\n" - " vec4 gl_Position;\n" - "};\n" - "void main(){\n" - " gl_Position = vec4(x[0][0]);\n" - "}\n"; - char const *fsSource = "#version 450\n" - "\n" - "layout(location=0) out vec4 color;\n" - "void main(){\n" - " color = vec4(1);\n" - "}\n"; - - VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); - VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); - - VkPipelineObj pipe(m_device); - pipe.AddColorAttachment(); - pipe.AddShader(&vs); - pipe.AddShader(&fs); - - pipe.AddVertexInputBindings(input_bindings, 1); - pipe.AddVertexInputAttribs(input_attribs, 4); - - VkDescriptorSetObj descriptorSet(m_device); - descriptorSet.AppendDummy(); - descriptorSet.CreateVKDescriptorSet(m_commandBuffer); - - pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); - - m_errorMonitor->VerifyNotFound(); -} - TEST_F(VkLayerTest, CreatePipelineFragmentOutputNotWritten) { TEST_DESCRIPTION("Test that an error is produced for a fragment shader which does not " "provide an output for one of the pipeline's color attachments"); @@ -16787,79 +12993,6 @@ TEST_F(VkLayerTest, CreatePipelineInputAttachmentMissing) { vkDestroyDescriptorSetLayout(m_device->device(), dsl, nullptr); } -TEST_F(VkLayerTest, CreatePipelineInputAttachmentPositive) { - TEST_DESCRIPTION("Positive test for a correctly matched input attachment"); - m_errorMonitor->ExpectSuccess(); - - ASSERT_NO_FATAL_FAILURE(InitState()); - - char const *vsSource = "#version 450\n" - "\n" - "out gl_PerVertex {\n" - " vec4 gl_Position;\n" - "};\n" - "void main(){\n" - " gl_Position = vec4(1);\n" - "}\n"; - char const *fsSource = "#version 450\n" - "\n" - "layout(input_attachment_index=0, set=0, binding=0) uniform subpassInput x;\n" - "layout(location=0) out vec4 color;\n" - "void main() {\n" - " color = subpassLoad(x);\n" - "}\n"; - - VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); - VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); - - VkPipelineObj pipe(m_device); - pipe.AddShader(&vs); - pipe.AddShader(&fs); - pipe.AddColorAttachment(); - ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); - - VkDescriptorSetLayoutBinding dslb = {0, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}; - VkDescriptorSetLayoutCreateInfo dslci = {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, nullptr, 0, 1, &dslb}; - VkDescriptorSetLayout dsl; - VkResult err = vkCreateDescriptorSetLayout(m_device->device(), &dslci, nullptr, &dsl); - ASSERT_VK_SUCCESS(err); - - VkPipelineLayoutCreateInfo plci = {VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, nullptr, 0, 1, &dsl, 0, nullptr}; - VkPipelineLayout pl; - err = vkCreatePipelineLayout(m_device->device(), &plci, nullptr, &pl); - ASSERT_VK_SUCCESS(err); - - VkAttachmentDescription descs[2] = { - {0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, - VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}, - {0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, - VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL}, - }; - VkAttachmentReference color = { - 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - }; - VkAttachmentReference input = { - 1, VK_IMAGE_LAYOUT_GENERAL, - }; - - VkSubpassDescription sd = {0, VK_PIPELINE_BIND_POINT_GRAPHICS, 1, &input, 1, &color, nullptr, nullptr, 0, nullptr}; - - VkRenderPassCreateInfo rpci = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 2, descs, 1, &sd, 0, nullptr}; - VkRenderPass rp; - err = vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); - ASSERT_VK_SUCCESS(err); - - // should be OK. would go wrong here if it's going to... - pipe.CreateVKPipeline(pl, rp); - - m_errorMonitor->VerifyNotFound(); - - vkDestroyRenderPass(m_device->device(), rp, nullptr); - vkDestroyPipelineLayout(m_device->device(), pl, nullptr); - vkDestroyDescriptorSetLayout(m_device->device(), dsl, nullptr); -} - TEST_F(VkLayerTest, CreatePipelineInputAttachmentTypeMismatch) { TEST_DESCRIPTION("Test that an error is produced for a shader consuming an input attachment " "with a format having a different fundamental type"); @@ -17027,47 +13160,6 @@ TEST_F(VkLayerTest, CreateComputePipelineMissingDescriptor) { } } -TEST_F(VkLayerTest, CreateComputePipelineMissingDescriptorUnusedPositive) { - TEST_DESCRIPTION("Test that pipeline validation accepts a compute pipeline which declares a " - "descriptor-backed resource which is not provided, but the shader does not " - "statically use it. This is interesting because it requires compute pipelines " - "to have a proper descriptor use walk, which they didn't for some time."); - m_errorMonitor->ExpectSuccess(); - - ASSERT_NO_FATAL_FAILURE(InitState()); - - char const *csSource = "#version 450\n" - "\n" - "layout(local_size_x=1) in;\n" - "layout(set=0, binding=0) buffer block { vec4 x; };\n" - "void main(){\n" - " // x is not used.\n" - "}\n"; - - VkShaderObj cs(m_device, csSource, VK_SHADER_STAGE_COMPUTE_BIT, this); - - VkDescriptorSetObj descriptorSet(m_device); - descriptorSet.CreateVKDescriptorSet(m_commandBuffer); - - VkComputePipelineCreateInfo cpci = {VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, - nullptr, - 0, - {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, nullptr, 0, - VK_SHADER_STAGE_COMPUTE_BIT, cs.handle(), "main", nullptr}, - descriptorSet.GetPipelineLayout(), - VK_NULL_HANDLE, - -1}; - - VkPipeline pipe; - VkResult err = vkCreateComputePipelines(m_device->device(), VK_NULL_HANDLE, 1, &cpci, nullptr, &pipe); - - m_errorMonitor->VerifyNotFound(); - - if (err == VK_SUCCESS) { - vkDestroyPipeline(m_device->device(), pipe, nullptr); - } -} - TEST_F(VkLayerTest, CreateComputePipelineDescriptorTypeMismatch) { TEST_DESCRIPTION("Test that an error is produced for a pipeline consuming a " "descriptor-backed resource of a mismatched type"); @@ -17118,171 +13210,6 @@ TEST_F(VkLayerTest, CreateComputePipelineDescriptorTypeMismatch) { vkDestroyDescriptorSetLayout(m_device->device(), dsl, nullptr); } -TEST_F(VkLayerTest, CreateComputePipelineCombinedImageSamplerConsumedAsSampler) { - TEST_DESCRIPTION("Test that pipeline validation accepts a shader consuming only the " - "sampler portion of a combined image + sampler"); - m_errorMonitor->ExpectSuccess(); - - ASSERT_NO_FATAL_FAILURE(InitState()); - - VkDescriptorSetLayoutBinding bindings[] = { - {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr}, - {1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr}, - {2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr}, - }; - VkDescriptorSetLayoutCreateInfo dslci = {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, nullptr, 0, 3, bindings}; - VkDescriptorSetLayout dsl; - VkResult err = vkCreateDescriptorSetLayout(m_device->device(), &dslci, nullptr, &dsl); - ASSERT_VK_SUCCESS(err); - - VkPipelineLayoutCreateInfo plci = {VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, nullptr, 0, 1, &dsl, 0, nullptr}; - VkPipelineLayout pl; - err = vkCreatePipelineLayout(m_device->device(), &plci, nullptr, &pl); - ASSERT_VK_SUCCESS(err); - - char const *csSource = "#version 450\n" - "\n" - "layout(local_size_x=1) in;\n" - "layout(set=0, binding=0) uniform sampler s;\n" - "layout(set=0, binding=1) uniform texture2D t;\n" - "layout(set=0, binding=2) buffer block { vec4 x; };\n" - "void main() {\n" - " x = texture(sampler2D(t, s), vec2(0));\n" - "}\n"; - VkShaderObj cs(m_device, csSource, VK_SHADER_STAGE_COMPUTE_BIT, this); - - VkComputePipelineCreateInfo cpci = {VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, - nullptr, - 0, - {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, nullptr, 0, - VK_SHADER_STAGE_COMPUTE_BIT, cs.handle(), "main", nullptr}, - pl, - VK_NULL_HANDLE, - -1}; - - VkPipeline pipe; - err = vkCreateComputePipelines(m_device->device(), VK_NULL_HANDLE, 1, &cpci, nullptr, &pipe); - - m_errorMonitor->VerifyNotFound(); - - if (err == VK_SUCCESS) { - vkDestroyPipeline(m_device->device(), pipe, nullptr); - } - - vkDestroyPipelineLayout(m_device->device(), pl, nullptr); - vkDestroyDescriptorSetLayout(m_device->device(), dsl, nullptr); -} - -TEST_F(VkLayerTest, CreateComputePipelineCombinedImageSamplerConsumedAsImage) { - TEST_DESCRIPTION("Test that pipeline validation accepts a shader consuming only the " - "image portion of a combined image + sampler"); - m_errorMonitor->ExpectSuccess(); - - ASSERT_NO_FATAL_FAILURE(InitState()); - - VkDescriptorSetLayoutBinding bindings[] = { - {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr}, - {1, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr}, - {2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr}, - }; - VkDescriptorSetLayoutCreateInfo dslci = {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, nullptr, 0, 3, bindings}; - VkDescriptorSetLayout dsl; - VkResult err = vkCreateDescriptorSetLayout(m_device->device(), &dslci, nullptr, &dsl); - ASSERT_VK_SUCCESS(err); - - VkPipelineLayoutCreateInfo plci = {VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, nullptr, 0, 1, &dsl, 0, nullptr}; - VkPipelineLayout pl; - err = vkCreatePipelineLayout(m_device->device(), &plci, nullptr, &pl); - ASSERT_VK_SUCCESS(err); - - char const *csSource = "#version 450\n" - "\n" - "layout(local_size_x=1) in;\n" - "layout(set=0, binding=0) uniform texture2D t;\n" - "layout(set=0, binding=1) uniform sampler s;\n" - "layout(set=0, binding=2) buffer block { vec4 x; };\n" - "void main() {\n" - " x = texture(sampler2D(t, s), vec2(0));\n" - "}\n"; - VkShaderObj cs(m_device, csSource, VK_SHADER_STAGE_COMPUTE_BIT, this); - - VkComputePipelineCreateInfo cpci = {VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, - nullptr, - 0, - {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, nullptr, 0, - VK_SHADER_STAGE_COMPUTE_BIT, cs.handle(), "main", nullptr}, - pl, - VK_NULL_HANDLE, - -1}; - - VkPipeline pipe; - err = vkCreateComputePipelines(m_device->device(), VK_NULL_HANDLE, 1, &cpci, nullptr, &pipe); - - m_errorMonitor->VerifyNotFound(); - - if (err == VK_SUCCESS) { - vkDestroyPipeline(m_device->device(), pipe, nullptr); - } - - vkDestroyPipelineLayout(m_device->device(), pl, nullptr); - vkDestroyDescriptorSetLayout(m_device->device(), dsl, nullptr); -} - -TEST_F(VkLayerTest, CreateComputePipelineCombinedImageSamplerConsumedAsBoth) { - TEST_DESCRIPTION("Test that pipeline validation accepts a shader consuming " - "both the sampler and the image of a combined image+sampler " - "but via separate variables"); - m_errorMonitor->ExpectSuccess(); - - ASSERT_NO_FATAL_FAILURE(InitState()); - - VkDescriptorSetLayoutBinding bindings[] = { - {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr}, - {1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr}, - }; - VkDescriptorSetLayoutCreateInfo dslci = {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, nullptr, 0, 2, bindings}; - VkDescriptorSetLayout dsl; - VkResult err = vkCreateDescriptorSetLayout(m_device->device(), &dslci, nullptr, &dsl); - ASSERT_VK_SUCCESS(err); - - VkPipelineLayoutCreateInfo plci = {VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, nullptr, 0, 1, &dsl, 0, nullptr}; - VkPipelineLayout pl; - err = vkCreatePipelineLayout(m_device->device(), &plci, nullptr, &pl); - ASSERT_VK_SUCCESS(err); - - char const *csSource = "#version 450\n" - "\n" - "layout(local_size_x=1) in;\n" - "layout(set=0, binding=0) uniform texture2D t;\n" - "layout(set=0, binding=0) uniform sampler s; // both binding 0!\n" - "layout(set=0, binding=1) buffer block { vec4 x; };\n" - "void main() {\n" - " x = texture(sampler2D(t, s), vec2(0));\n" - "}\n"; - VkShaderObj cs(m_device, csSource, VK_SHADER_STAGE_COMPUTE_BIT, this); - - VkComputePipelineCreateInfo cpci = {VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, - nullptr, - 0, - {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, nullptr, 0, - VK_SHADER_STAGE_COMPUTE_BIT, cs.handle(), "main", nullptr}, - pl, - VK_NULL_HANDLE, - -1}; - - VkPipeline pipe; - err = vkCreateComputePipelines(m_device->device(), VK_NULL_HANDLE, 1, &cpci, nullptr, &pipe); - - m_errorMonitor->VerifyNotFound(); - - if (err == VK_SUCCESS) { - vkDestroyPipeline(m_device->device(), pipe, nullptr); - } - - vkDestroyPipelineLayout(m_device->device(), pl, nullptr); - vkDestroyDescriptorSetLayout(m_device->device(), dsl, nullptr); -} - TEST_F(VkLayerTest, DrawTimeImageViewTypeMismatchWithPipeline) { TEST_DESCRIPTION("Test that an error is produced when an image view type " "does not match the dimensionality declared in the shader"); @@ -18939,6 +14866,4185 @@ TEST_F(VkLayerTest, ClearImageErrors) { } #endif // IMAGE_TESTS + +// WSI Enabled Tests +// +TEST_F(VkWsiEnabledLayerTest, TestEnabledWsi) { + +#if defined(VK_USE_PLATFORM_XCB_KHR) + VkSurfaceKHR surface = VK_NULL_HANDLE; + + VkResult err; + bool pass; + VkSwapchainKHR swapchain = VK_NULL_HANDLE; + VkSwapchainCreateInfoKHR swapchain_create_info = {}; + // uint32_t swapchain_image_count = 0; + // VkImage swapchain_images[1] = {VK_NULL_HANDLE}; + // uint32_t image_index = 0; + // VkPresentInfoKHR present_info = {}; + + ASSERT_NO_FATAL_FAILURE(InitState()); + + // Use the create function from one of the VK_KHR_*_surface extension in + // order to create a surface, testing all known errors in the process, + // before successfully creating a surface: + // First, try to create a surface without a VkXcbSurfaceCreateInfoKHR: + m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "required parameter pCreateInfo specified as NULL"); + err = vkCreateXcbSurfaceKHR(instance(), NULL, NULL, &surface); + pass = (err != VK_SUCCESS); + ASSERT_TRUE(pass); + m_errorMonitor->VerifyFound(); + + // Next, try to create a surface with the wrong + // VkXcbSurfaceCreateInfoKHR::sType: + VkXcbSurfaceCreateInfoKHR xcb_create_info = {}; + xcb_create_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "parameter pCreateInfo->sType must be"); + err = vkCreateXcbSurfaceKHR(instance(), &xcb_create_info, NULL, &surface); + pass = (err != VK_SUCCESS); + ASSERT_TRUE(pass); + m_errorMonitor->VerifyFound(); + + // Create a native window, and then correctly create a surface: + xcb_connection_t *connection; + xcb_screen_t *screen; + xcb_window_t xcb_window; + xcb_intern_atom_reply_t *atom_wm_delete_window; + + const xcb_setup_t *setup; + xcb_screen_iterator_t iter; + int scr; + uint32_t value_mask, value_list[32]; + int width = 1; + int height = 1; + + connection = xcb_connect(NULL, &scr); + ASSERT_TRUE(connection != NULL); + setup = xcb_get_setup(connection); + iter = xcb_setup_roots_iterator(setup); + while (scr-- > 0) + xcb_screen_next(&iter); + screen = iter.data; + + xcb_window = xcb_generate_id(connection); + + value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; + value_list[0] = screen->black_pixel; + value_list[1] = XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY; + + xcb_create_window(connection, XCB_COPY_FROM_PARENT, xcb_window, screen->root, 0, 0, width, height, 0, + XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, value_mask, value_list); + + /* Magic code that will send notification when window is destroyed */ + xcb_intern_atom_cookie_t cookie = xcb_intern_atom(connection, 1, 12, "WM_PROTOCOLS"); + xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(connection, cookie, 0); + + xcb_intern_atom_cookie_t cookie2 = xcb_intern_atom(connection, 0, 16, "WM_DELETE_WINDOW"); + atom_wm_delete_window = xcb_intern_atom_reply(connection, cookie2, 0); + xcb_change_property(connection, XCB_PROP_MODE_REPLACE, xcb_window, (*reply).atom, 4, 32, 1, &(*atom_wm_delete_window).atom); + free(reply); + + xcb_map_window(connection, xcb_window); + + // Force the x/y coordinates to 100,100 results are identical in consecutive + // runs + const uint32_t coords[] = { 100, 100 }; + xcb_configure_window(connection, xcb_window, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, coords); + + // Finally, try to correctly create a surface: + xcb_create_info.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; + xcb_create_info.pNext = NULL; + xcb_create_info.flags = 0; + xcb_create_info.connection = connection; + xcb_create_info.window = xcb_window; + err = vkCreateXcbSurfaceKHR(instance(), &xcb_create_info, NULL, &surface); + pass = (err == VK_SUCCESS); + ASSERT_TRUE(pass); + + // Check if surface supports presentation: + + // 1st, do so without having queried the queue families: + VkBool32 supported = false; + // TODO: Get the following error to come out: + m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, + "called before calling the vkGetPhysicalDeviceQueueFamilyProperties " + "function"); + err = vkGetPhysicalDeviceSurfaceSupportKHR(gpu(), 0, surface, &supported); + pass = (err != VK_SUCCESS); + // ASSERT_TRUE(pass); + // m_errorMonitor->VerifyFound(); + + // Next, query a queue family index that's too large: + m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "called with a queueFamilyIndex that is too large"); + err = vkGetPhysicalDeviceSurfaceSupportKHR(gpu(), 100000, surface, &supported); + pass = (err != VK_SUCCESS); + ASSERT_TRUE(pass); + m_errorMonitor->VerifyFound(); + + // Finally, do so correctly: + // FIXME: THIS ISN'T CORRECT--MUST QUERY UNTIL WE FIND A QUEUE FAMILY THAT'S + // SUPPORTED + err = vkGetPhysicalDeviceSurfaceSupportKHR(gpu(), 0, surface, &supported); + pass = (err == VK_SUCCESS); + ASSERT_TRUE(pass); + + // Before proceeding, try to create a swapchain without having called + // vkGetPhysicalDeviceSurfaceCapabilitiesKHR(): + swapchain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + swapchain_create_info.pNext = NULL; + swapchain_create_info.flags = 0; + swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + swapchain_create_info.surface = surface; + swapchain_create_info.imageArrayLayers = 1; + swapchain_create_info.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, + "called before calling vkGetPhysicalDeviceSurfaceCapabilitiesKHR()."); + err = vkCreateSwapchainKHR(m_device->device(), &swapchain_create_info, NULL, &swapchain); + pass = (err != VK_SUCCESS); + ASSERT_TRUE(pass); + m_errorMonitor->VerifyFound(); + + // Get the surface capabilities: + VkSurfaceCapabilitiesKHR surface_capabilities; + + // Do so correctly (only error logged by this entrypoint is if the + // extension isn't enabled): + err = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(gpu(), surface, &surface_capabilities); + pass = (err == VK_SUCCESS); + ASSERT_TRUE(pass); + + // Get the surface formats: + uint32_t surface_format_count; + + // First, try without a pointer to surface_format_count: + m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "required parameter pSurfaceFormatCount " + "specified as NULL"); + vkGetPhysicalDeviceSurfaceFormatsKHR(gpu(), surface, NULL, NULL); + pass = (err == VK_SUCCESS); + ASSERT_TRUE(pass); + m_errorMonitor->VerifyFound(); + + // Next, call with a non-NULL pSurfaceFormats, even though we haven't + // correctly done a 1st try (to get the count): + m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_WARNING_BIT_EXT, "but no prior positive value has been seen for"); + surface_format_count = 0; + vkGetPhysicalDeviceSurfaceFormatsKHR(gpu(), surface, &surface_format_count, (VkSurfaceFormatKHR *)&surface_format_count); + pass = (err == VK_SUCCESS); + ASSERT_TRUE(pass); + m_errorMonitor->VerifyFound(); + + // Next, correctly do a 1st try (with a NULL pointer to surface_formats): + vkGetPhysicalDeviceSurfaceFormatsKHR(gpu(), surface, &surface_format_count, NULL); + pass = (err == VK_SUCCESS); + ASSERT_TRUE(pass); + + // Allocate memory for the correct number of VkSurfaceFormatKHR's: + VkSurfaceFormatKHR *surface_formats = (VkSurfaceFormatKHR *)malloc(surface_format_count * sizeof(VkSurfaceFormatKHR)); + + // Next, do a 2nd try with surface_format_count being set too high: + surface_format_count += 5; + m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "that is greater than the value"); + vkGetPhysicalDeviceSurfaceFormatsKHR(gpu(), surface, &surface_format_count, surface_formats); + pass = (err == VK_SUCCESS); + ASSERT_TRUE(pass); + m_errorMonitor->VerifyFound(); + + // Finally, do a correct 1st and 2nd try: + vkGetPhysicalDeviceSurfaceFormatsKHR(gpu(), surface, &surface_format_count, NULL); + pass = (err == VK_SUCCESS); + ASSERT_TRUE(pass); + vkGetPhysicalDeviceSurfaceFormatsKHR(gpu(), surface, &surface_format_count, surface_formats); + pass = (err == VK_SUCCESS); + ASSERT_TRUE(pass); + + // Get the surface present modes: + uint32_t surface_present_mode_count; + + // First, try without a pointer to surface_format_count: + m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "required parameter pPresentModeCount " + "specified as NULL"); + + vkGetPhysicalDeviceSurfacePresentModesKHR(gpu(), surface, NULL, NULL); + pass = (err == VK_SUCCESS); + ASSERT_TRUE(pass); + m_errorMonitor->VerifyFound(); + + // Next, call with a non-NULL VkPresentModeKHR, even though we haven't + // correctly done a 1st try (to get the count): + m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_WARNING_BIT_EXT, "but no prior positive value has been seen for"); + surface_present_mode_count = 0; + vkGetPhysicalDeviceSurfacePresentModesKHR(gpu(), surface, &surface_present_mode_count, + (VkPresentModeKHR *)&surface_present_mode_count); + pass = (err == VK_SUCCESS); + ASSERT_TRUE(pass); + m_errorMonitor->VerifyFound(); + + // Next, correctly do a 1st try (with a NULL pointer to surface_formats): + vkGetPhysicalDeviceSurfacePresentModesKHR(gpu(), surface, &surface_present_mode_count, NULL); + pass = (err == VK_SUCCESS); + ASSERT_TRUE(pass); + + // Allocate memory for the correct number of VkSurfaceFormatKHR's: + VkPresentModeKHR *surface_present_modes = (VkPresentModeKHR *)malloc(surface_present_mode_count * sizeof(VkPresentModeKHR)); + + // Next, do a 2nd try with surface_format_count being set too high: + surface_present_mode_count += 5; + m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "that is greater than the value"); + vkGetPhysicalDeviceSurfacePresentModesKHR(gpu(), surface, &surface_present_mode_count, surface_present_modes); + pass = (err == VK_SUCCESS); + ASSERT_TRUE(pass); + m_errorMonitor->VerifyFound(); + + // Finally, do a correct 1st and 2nd try: + vkGetPhysicalDeviceSurfacePresentModesKHR(gpu(), surface, &surface_present_mode_count, NULL); + pass = (err == VK_SUCCESS); + ASSERT_TRUE(pass); + vkGetPhysicalDeviceSurfacePresentModesKHR(gpu(), surface, &surface_present_mode_count, surface_present_modes); + pass = (err == VK_SUCCESS); + ASSERT_TRUE(pass); + + // Create a swapchain: + + // First, try without a pointer to swapchain_create_info: + m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "required parameter pCreateInfo " + "specified as NULL"); + + err = vkCreateSwapchainKHR(m_device->device(), NULL, NULL, &swapchain); + pass = (err != VK_SUCCESS); + ASSERT_TRUE(pass); + m_errorMonitor->VerifyFound(); + + // Next, call with a non-NULL swapchain_create_info, that has the wrong + // sType: + swapchain_create_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "parameter pCreateInfo->sType must be"); + + err = vkCreateSwapchainKHR(m_device->device(), &swapchain_create_info, NULL, &swapchain); + pass = (err != VK_SUCCESS); + ASSERT_TRUE(pass); + m_errorMonitor->VerifyFound(); + + // Next, call with a NULL swapchain pointer: + swapchain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + swapchain_create_info.pNext = NULL; + swapchain_create_info.flags = 0; + m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "required parameter pSwapchain " + "specified as NULL"); + + err = vkCreateSwapchainKHR(m_device->device(), &swapchain_create_info, NULL, NULL); + pass = (err != VK_SUCCESS); + ASSERT_TRUE(pass); + m_errorMonitor->VerifyFound(); + + // TODO: Enhance swapchain layer so that + // swapchain_create_info.queueFamilyIndexCount is checked against something? + + // Next, call with a queue family index that's too large: + uint32_t queueFamilyIndex[2] = { 100000, 0 }; + swapchain_create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT; + swapchain_create_info.queueFamilyIndexCount = 2; + swapchain_create_info.pQueueFamilyIndices = queueFamilyIndex; + m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "called with a queueFamilyIndex that is too large"); + err = vkCreateSwapchainKHR(m_device->device(), &swapchain_create_info, NULL, &swapchain); + pass = (err != VK_SUCCESS); + ASSERT_TRUE(pass); + m_errorMonitor->VerifyFound(); + + // Next, call a queueFamilyIndexCount that's too small for CONCURRENT: + swapchain_create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT; + swapchain_create_info.queueFamilyIndexCount = 1; + m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, + "but with a bad value(s) for pCreateInfo->queueFamilyIndexCount or " + "pCreateInfo->pQueueFamilyIndices)."); + err = vkCreateSwapchainKHR(m_device->device(), &swapchain_create_info, NULL, &swapchain); + pass = (err != VK_SUCCESS); + ASSERT_TRUE(pass); + m_errorMonitor->VerifyFound(); + + // Next, call with an invalid imageSharingMode: + swapchain_create_info.imageSharingMode = VK_SHARING_MODE_MAX_ENUM; + swapchain_create_info.queueFamilyIndexCount = 1; + m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, + "called with a non-supported pCreateInfo->imageSharingMode (i.e."); + err = vkCreateSwapchainKHR(m_device->device(), &swapchain_create_info, NULL, &swapchain); + pass = (err != VK_SUCCESS); + ASSERT_TRUE(pass); + m_errorMonitor->VerifyFound(); + // Fix for the future: + // FIXME: THIS ISN'T CORRECT--MUST QUERY UNTIL WE FIND A QUEUE FAMILY THAT'S + // SUPPORTED + swapchain_create_info.queueFamilyIndexCount = 0; + queueFamilyIndex[0] = 0; + swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + + // TODO: CONTINUE TESTING VALIDATION OF vkCreateSwapchainKHR() ... + // Get the images from a swapchain: + // Acquire an image from a swapchain: + // Present an image to a swapchain: + // Destroy the swapchain: + + // TODOs: + // + // - Try destroying the device without first destroying the swapchain + // + // - Try destroying the device without first destroying the surface + // + // - Try destroying the surface without first destroying the swapchain + + // Destroy the surface: + vkDestroySurfaceKHR(instance(), surface, NULL); + + // Tear down the window: + xcb_destroy_window(connection, xcb_window); + xcb_disconnect(connection); + +#else // VK_USE_PLATFORM_XCB_KHR + return; +#endif // VK_USE_PLATFORM_XCB_KHR +} + +// +// POSITIVE VALIDATION TESTS +// +// These tests do not expect to encounter ANY validation errors pass only if this is true + +// This is a positive test. No failures are expected. +TEST_F(VkPositiveLayerTest, IgnoreUnrelatedDescriptor) { + TEST_DESCRIPTION("Ensure that the vkUpdateDescriptorSets validation code " + "is ignoring VkWriteDescriptorSet members that are not " + "related to the descriptor type specified by " + "VkWriteDescriptorSet::descriptorType. Correct " + "validation behavior will result in the test running to " + "completion without validation errors."); + + const uintptr_t invalid_ptr = 0xcdcdcdcd; + + ASSERT_NO_FATAL_FAILURE(InitState()); + + // Image Case + { + m_errorMonitor->ExpectSuccess(); + + VkImage image; + const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM; + const int32_t tex_width = 32; + const int32_t tex_height = 32; + VkImageCreateInfo image_create_info = {}; + image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + image_create_info.pNext = NULL; + image_create_info.imageType = VK_IMAGE_TYPE_2D; + image_create_info.format = tex_format; + image_create_info.extent.width = tex_width; + image_create_info.extent.height = tex_height; + image_create_info.extent.depth = 1; + image_create_info.mipLevels = 1; + image_create_info.arrayLayers = 1; + image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; + image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; + image_create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT; + image_create_info.flags = 0; + VkResult err = vkCreateImage(m_device->device(), &image_create_info, NULL, &image); + ASSERT_VK_SUCCESS(err); + + VkMemoryRequirements memory_reqs; + VkDeviceMemory image_memory; + bool pass; + VkMemoryAllocateInfo memory_info = {}; + memory_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + memory_info.pNext = NULL; + memory_info.allocationSize = 0; + memory_info.memoryTypeIndex = 0; + vkGetImageMemoryRequirements(m_device->device(), image, &memory_reqs); + memory_info.allocationSize = memory_reqs.size; + pass = m_device->phy().set_memory_type(memory_reqs.memoryTypeBits, &memory_info, 0); + ASSERT_TRUE(pass); + err = vkAllocateMemory(m_device->device(), &memory_info, NULL, &image_memory); + ASSERT_VK_SUCCESS(err); + err = vkBindImageMemory(m_device->device(), image, image_memory, 0); + ASSERT_VK_SUCCESS(err); + + VkImageViewCreateInfo image_view_create_info = {}; + image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + image_view_create_info.image = image; + image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; + image_view_create_info.format = tex_format; + image_view_create_info.subresourceRange.layerCount = 1; + image_view_create_info.subresourceRange.baseMipLevel = 0; + image_view_create_info.subresourceRange.levelCount = 1; + image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + + VkImageView view; + err = vkCreateImageView(m_device->device(), &image_view_create_info, NULL, &view); + ASSERT_VK_SUCCESS(err); + + VkDescriptorPoolSize ds_type_count = {}; + ds_type_count.type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + ds_type_count.descriptorCount = 1; + + VkDescriptorPoolCreateInfo ds_pool_ci = {}; + ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + ds_pool_ci.pNext = NULL; + ds_pool_ci.maxSets = 1; + ds_pool_ci.poolSizeCount = 1; + ds_pool_ci.pPoolSizes = &ds_type_count; + + VkDescriptorPool ds_pool; + err = vkCreateDescriptorPool(m_device->device(), &ds_pool_ci, NULL, &ds_pool); + ASSERT_VK_SUCCESS(err); + + VkDescriptorSetLayoutBinding dsl_binding = {}; + dsl_binding.binding = 0; + dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + dsl_binding.descriptorCount = 1; + dsl_binding.stageFlags = VK_SHADER_STAGE_ALL; + dsl_binding.pImmutableSamplers = NULL; + + VkDescriptorSetLayoutCreateInfo ds_layout_ci = {}; + ds_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + ds_layout_ci.pNext = NULL; + ds_layout_ci.bindingCount = 1; + ds_layout_ci.pBindings = &dsl_binding; + VkDescriptorSetLayout ds_layout; + err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout); + ASSERT_VK_SUCCESS(err); + + VkDescriptorSet descriptor_set; + VkDescriptorSetAllocateInfo alloc_info = {}; + alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + alloc_info.descriptorSetCount = 1; + alloc_info.descriptorPool = ds_pool; + alloc_info.pSetLayouts = &ds_layout; + err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, &descriptor_set); + ASSERT_VK_SUCCESS(err); + + VkDescriptorImageInfo image_info = {}; + image_info.imageView = view; + image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + VkWriteDescriptorSet descriptor_write; + memset(&descriptor_write, 0, sizeof(descriptor_write)); + descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptor_write.dstSet = descriptor_set; + descriptor_write.dstBinding = 0; + descriptor_write.descriptorCount = 1; + descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + descriptor_write.pImageInfo = &image_info; + + // Set pBufferInfo and pTexelBufferView to invalid values, which should + // be + // ignored for descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE. + // This will most likely produce a crash if the parameter_validation + // layer + // does not correctly ignore pBufferInfo. + descriptor_write.pBufferInfo = reinterpret_cast<const VkDescriptorBufferInfo *>(invalid_ptr); + descriptor_write.pTexelBufferView = reinterpret_cast<const VkBufferView *>(invalid_ptr); + + vkUpdateDescriptorSets(m_device->device(), 1, &descriptor_write, 0, NULL); + + m_errorMonitor->VerifyNotFound(); + + vkDestroyDescriptorSetLayout(m_device->device(), ds_layout, NULL); + vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL); + vkDestroyImageView(m_device->device(), view, NULL); + vkDestroyImage(m_device->device(), image, NULL); + vkFreeMemory(m_device->device(), image_memory, NULL); + } + + // Buffer Case + { + m_errorMonitor->ExpectSuccess(); + + VkBuffer buffer; + uint32_t queue_family_index = 0; + VkBufferCreateInfo buffer_create_info = {}; + buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buffer_create_info.size = 1024; + buffer_create_info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + buffer_create_info.queueFamilyIndexCount = 1; + buffer_create_info.pQueueFamilyIndices = &queue_family_index; + + VkResult err = vkCreateBuffer(m_device->device(), &buffer_create_info, NULL, &buffer); + ASSERT_VK_SUCCESS(err); + + VkMemoryRequirements memory_reqs; + VkDeviceMemory buffer_memory; + bool pass; + VkMemoryAllocateInfo memory_info = {}; + memory_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + memory_info.pNext = NULL; + memory_info.allocationSize = 0; + memory_info.memoryTypeIndex = 0; + + vkGetBufferMemoryRequirements(m_device->device(), buffer, &memory_reqs); + memory_info.allocationSize = memory_reqs.size; + pass = m_device->phy().set_memory_type(memory_reqs.memoryTypeBits, &memory_info, 0); + ASSERT_TRUE(pass); + + err = vkAllocateMemory(m_device->device(), &memory_info, NULL, &buffer_memory); + ASSERT_VK_SUCCESS(err); + err = vkBindBufferMemory(m_device->device(), buffer, buffer_memory, 0); + ASSERT_VK_SUCCESS(err); + + VkDescriptorPoolSize ds_type_count = {}; + ds_type_count.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + ds_type_count.descriptorCount = 1; + + VkDescriptorPoolCreateInfo ds_pool_ci = {}; + ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + ds_pool_ci.pNext = NULL; + ds_pool_ci.maxSets = 1; + ds_pool_ci.poolSizeCount = 1; + ds_pool_ci.pPoolSizes = &ds_type_count; + + VkDescriptorPool ds_pool; + err = vkCreateDescriptorPool(m_device->device(), &ds_pool_ci, NULL, &ds_pool); + ASSERT_VK_SUCCESS(err); + + VkDescriptorSetLayoutBinding dsl_binding = {}; + dsl_binding.binding = 0; + dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + dsl_binding.descriptorCount = 1; + dsl_binding.stageFlags = VK_SHADER_STAGE_ALL; + dsl_binding.pImmutableSamplers = NULL; + + VkDescriptorSetLayoutCreateInfo ds_layout_ci = {}; + ds_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + ds_layout_ci.pNext = NULL; + ds_layout_ci.bindingCount = 1; + ds_layout_ci.pBindings = &dsl_binding; + VkDescriptorSetLayout ds_layout; + err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout); + ASSERT_VK_SUCCESS(err); + + VkDescriptorSet descriptor_set; + VkDescriptorSetAllocateInfo alloc_info = {}; + alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + alloc_info.descriptorSetCount = 1; + alloc_info.descriptorPool = ds_pool; + alloc_info.pSetLayouts = &ds_layout; + err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, &descriptor_set); + ASSERT_VK_SUCCESS(err); + + VkDescriptorBufferInfo buffer_info = {}; + buffer_info.buffer = buffer; + buffer_info.offset = 0; + buffer_info.range = 1024; + + VkWriteDescriptorSet descriptor_write; + memset(&descriptor_write, 0, sizeof(descriptor_write)); + descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptor_write.dstSet = descriptor_set; + descriptor_write.dstBinding = 0; + descriptor_write.descriptorCount = 1; + descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + descriptor_write.pBufferInfo = &buffer_info; + + // Set pImageInfo and pTexelBufferView to invalid values, which should + // be + // ignored for descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER. + // This will most likely produce a crash if the parameter_validation + // layer + // does not correctly ignore pImageInfo. + descriptor_write.pImageInfo = reinterpret_cast<const VkDescriptorImageInfo *>(invalid_ptr); + descriptor_write.pTexelBufferView = reinterpret_cast<const VkBufferView *>(invalid_ptr); + + vkUpdateDescriptorSets(m_device->device(), 1, &descriptor_write, 0, NULL); + + m_errorMonitor->VerifyNotFound(); + + vkFreeDescriptorSets(m_device->device(), ds_pool, 1, &descriptor_set); + vkDestroyDescriptorSetLayout(m_device->device(), ds_layout, NULL); + vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL); + vkDestroyBuffer(m_device->device(), buffer, NULL); + vkFreeMemory(m_device->device(), buffer_memory, NULL); + } + + // Texel Buffer Case + { + m_errorMonitor->ExpectSuccess(); + + VkBuffer buffer; + uint32_t queue_family_index = 0; + VkBufferCreateInfo buffer_create_info = {}; + buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + 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; + + VkResult err = vkCreateBuffer(m_device->device(), &buffer_create_info, NULL, &buffer); + ASSERT_VK_SUCCESS(err); + + VkMemoryRequirements memory_reqs; + VkDeviceMemory buffer_memory; + bool pass; + VkMemoryAllocateInfo memory_info = {}; + memory_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + memory_info.pNext = NULL; + memory_info.allocationSize = 0; + memory_info.memoryTypeIndex = 0; + + vkGetBufferMemoryRequirements(m_device->device(), buffer, &memory_reqs); + memory_info.allocationSize = memory_reqs.size; + pass = m_device->phy().set_memory_type(memory_reqs.memoryTypeBits, &memory_info, 0); + ASSERT_TRUE(pass); + + err = vkAllocateMemory(m_device->device(), &memory_info, NULL, &buffer_memory); + ASSERT_VK_SUCCESS(err); + err = vkBindBufferMemory(m_device->device(), buffer, buffer_memory, 0); + ASSERT_VK_SUCCESS(err); + + VkBufferViewCreateInfo buff_view_ci = {}; + buff_view_ci.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO; + buff_view_ci.buffer = buffer; + buff_view_ci.format = VK_FORMAT_R8_UNORM; + buff_view_ci.range = VK_WHOLE_SIZE; + VkBufferView buffer_view; + err = vkCreateBufferView(m_device->device(), &buff_view_ci, NULL, &buffer_view); + + VkDescriptorPoolSize ds_type_count = {}; + ds_type_count.type = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; + ds_type_count.descriptorCount = 1; + + VkDescriptorPoolCreateInfo ds_pool_ci = {}; + ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + ds_pool_ci.pNext = NULL; + ds_pool_ci.maxSets = 1; + ds_pool_ci.poolSizeCount = 1; + ds_pool_ci.pPoolSizes = &ds_type_count; + + VkDescriptorPool ds_pool; + err = vkCreateDescriptorPool(m_device->device(), &ds_pool_ci, NULL, &ds_pool); + ASSERT_VK_SUCCESS(err); + + VkDescriptorSetLayoutBinding dsl_binding = {}; + dsl_binding.binding = 0; + dsl_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; + dsl_binding.descriptorCount = 1; + dsl_binding.stageFlags = VK_SHADER_STAGE_ALL; + dsl_binding.pImmutableSamplers = NULL; + + VkDescriptorSetLayoutCreateInfo ds_layout_ci = {}; + ds_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + ds_layout_ci.pNext = NULL; + ds_layout_ci.bindingCount = 1; + ds_layout_ci.pBindings = &dsl_binding; + VkDescriptorSetLayout ds_layout; + err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout); + ASSERT_VK_SUCCESS(err); + + VkDescriptorSet descriptor_set; + VkDescriptorSetAllocateInfo alloc_info = {}; + alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + alloc_info.descriptorSetCount = 1; + alloc_info.descriptorPool = ds_pool; + alloc_info.pSetLayouts = &ds_layout; + err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, &descriptor_set); + ASSERT_VK_SUCCESS(err); + + VkWriteDescriptorSet descriptor_write; + memset(&descriptor_write, 0, sizeof(descriptor_write)); + descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptor_write.dstSet = descriptor_set; + descriptor_write.dstBinding = 0; + descriptor_write.descriptorCount = 1; + descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; + descriptor_write.pTexelBufferView = &buffer_view; + + // Set pImageInfo and pBufferInfo to invalid values, which should be + // ignored for descriptorType == + // VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER. + // This will most likely produce a crash if the parameter_validation + // layer + // does not correctly ignore pImageInfo and pBufferInfo. + descriptor_write.pImageInfo = reinterpret_cast<const VkDescriptorImageInfo *>(invalid_ptr); + descriptor_write.pBufferInfo = reinterpret_cast<const VkDescriptorBufferInfo *>(invalid_ptr); + + vkUpdateDescriptorSets(m_device->device(), 1, &descriptor_write, 0, NULL); + + m_errorMonitor->VerifyNotFound(); + + vkFreeDescriptorSets(m_device->device(), ds_pool, 1, &descriptor_set); + vkDestroyDescriptorSetLayout(m_device->device(), ds_layout, NULL); + vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL); + vkDestroyBufferView(m_device->device(), buffer_view, NULL); + vkDestroyBuffer(m_device->device(), buffer, NULL); + vkFreeMemory(m_device->device(), buffer_memory, NULL); + } +} + +// This is a positive test. No failures are expected. +TEST_F(VkPositiveLayerTest, EmptyDescriptorUpdateTest) { + TEST_DESCRIPTION("Update last descriptor in a set that includes an empty binding"); + VkResult err; + + ASSERT_NO_FATAL_FAILURE(InitState()); + m_errorMonitor->ExpectSuccess(); + VkDescriptorPoolSize ds_type_count = {}; + ds_type_count.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + ds_type_count.descriptorCount = 2; + + VkDescriptorPoolCreateInfo ds_pool_ci = {}; + ds_pool_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + ds_pool_ci.pNext = NULL; + ds_pool_ci.maxSets = 1; + ds_pool_ci.poolSizeCount = 1; + ds_pool_ci.pPoolSizes = &ds_type_count; + + VkDescriptorPool ds_pool; + err = vkCreateDescriptorPool(m_device->device(), &ds_pool_ci, NULL, &ds_pool); + ASSERT_VK_SUCCESS(err); + + // Create layout with two uniform buffer descriptors w/ empty binding between them + static const uint32_t NUM_BINDINGS = 3; + VkDescriptorSetLayoutBinding dsl_binding[NUM_BINDINGS] = {}; + dsl_binding[0].binding = 0; + dsl_binding[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + dsl_binding[0].descriptorCount = 1; + dsl_binding[0].stageFlags = VK_SHADER_STAGE_ALL; + dsl_binding[0].pImmutableSamplers = NULL; + dsl_binding[1].binding = 1; + dsl_binding[1].descriptorCount = 0; // empty binding + dsl_binding[2].binding = 2; + dsl_binding[2].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + dsl_binding[2].descriptorCount = 1; + dsl_binding[2].stageFlags = VK_SHADER_STAGE_ALL; + dsl_binding[2].pImmutableSamplers = NULL; + + VkDescriptorSetLayoutCreateInfo ds_layout_ci = {}; + ds_layout_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + ds_layout_ci.pNext = NULL; + ds_layout_ci.bindingCount = NUM_BINDINGS; + ds_layout_ci.pBindings = dsl_binding; + VkDescriptorSetLayout ds_layout; + err = vkCreateDescriptorSetLayout(m_device->device(), &ds_layout_ci, NULL, &ds_layout); + ASSERT_VK_SUCCESS(err); + + VkDescriptorSet descriptor_set = {}; + VkDescriptorSetAllocateInfo alloc_info = {}; + alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + alloc_info.descriptorSetCount = 1; + alloc_info.descriptorPool = ds_pool; + alloc_info.pSetLayouts = &ds_layout; + err = vkAllocateDescriptorSets(m_device->device(), &alloc_info, &descriptor_set); + ASSERT_VK_SUCCESS(err); + + // Create a buffer to be used for update + VkBufferCreateInfo buff_ci = {}; + buff_ci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buff_ci.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + buff_ci.size = 256; + buff_ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + VkBuffer buffer; + err = vkCreateBuffer(m_device->device(), &buff_ci, NULL, &buffer); + ASSERT_VK_SUCCESS(err); + // Have to bind memory to buffer before descriptor update + VkMemoryAllocateInfo mem_alloc = {}; + mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + mem_alloc.pNext = NULL; + mem_alloc.allocationSize = 512; // one allocation for both buffers + mem_alloc.memoryTypeIndex = 0; + + VkMemoryRequirements mem_reqs; + vkGetBufferMemoryRequirements(m_device->device(), buffer, &mem_reqs); + bool pass = m_device->phy().set_memory_type(mem_reqs.memoryTypeBits, &mem_alloc, 0); + if (!pass) { + vkDestroyBuffer(m_device->device(), buffer, NULL); + return; + } + + VkDeviceMemory mem; + err = vkAllocateMemory(m_device->device(), &mem_alloc, NULL, &mem); + ASSERT_VK_SUCCESS(err); + err = vkBindBufferMemory(m_device->device(), buffer, mem, 0); + ASSERT_VK_SUCCESS(err); + + // Only update the descriptor at binding 2 + VkDescriptorBufferInfo buff_info = {}; + buff_info.buffer = buffer; + buff_info.offset = 0; + buff_info.range = VK_WHOLE_SIZE; + VkWriteDescriptorSet descriptor_write = {}; + descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptor_write.dstBinding = 2; + descriptor_write.descriptorCount = 1; + descriptor_write.pTexelBufferView = nullptr; + descriptor_write.pBufferInfo = &buff_info; + descriptor_write.pImageInfo = nullptr; + descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + descriptor_write.dstSet = descriptor_set; + + vkUpdateDescriptorSets(m_device->device(), 1, &descriptor_write, 0, NULL); + + m_errorMonitor->VerifyNotFound(); + // Cleanup + vkFreeMemory(m_device->device(), mem, NULL); + vkDestroyDescriptorSetLayout(m_device->device(), ds_layout, NULL); + vkDestroyBuffer(m_device->device(), buffer, NULL); + vkDestroyDescriptorPool(m_device->device(), ds_pool, NULL); +} + +// This is a positive test. No failures are expected. +TEST_F(VkPositiveLayerTest, TestAliasedMemoryTracking) { + VkResult err; + bool pass; + + TEST_DESCRIPTION("Create a buffer, allocate memory, bind memory, destroy " + "the buffer, create an image, and bind the same memory to " + "it"); + + m_errorMonitor->ExpectSuccess(); + + ASSERT_NO_FATAL_FAILURE(InitState()); + + VkBuffer buffer; + VkImage image; + VkDeviceMemory mem; + VkMemoryRequirements mem_reqs; + + VkBufferCreateInfo buf_info = {}; + buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buf_info.pNext = NULL; + buf_info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + buf_info.size = 256; + buf_info.queueFamilyIndexCount = 0; + buf_info.pQueueFamilyIndices = NULL; + buf_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + buf_info.flags = 0; + err = vkCreateBuffer(m_device->device(), &buf_info, NULL, &buffer); + ASSERT_VK_SUCCESS(err); + + vkGetBufferMemoryRequirements(m_device->device(), buffer, &mem_reqs); + + VkMemoryAllocateInfo alloc_info = {}; + alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + alloc_info.pNext = NULL; + alloc_info.memoryTypeIndex = 0; + + // Ensure memory is big enough for both bindings + alloc_info.allocationSize = 0x10000; + + pass = m_device->phy().set_memory_type(mem_reqs.memoryTypeBits, &alloc_info, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); + if (!pass) { + vkDestroyBuffer(m_device->device(), buffer, NULL); + return; + } + + err = vkAllocateMemory(m_device->device(), &alloc_info, NULL, &mem); + ASSERT_VK_SUCCESS(err); + + uint8_t *pData; + err = vkMapMemory(m_device->device(), mem, 0, mem_reqs.size, 0, (void **)&pData); + ASSERT_VK_SUCCESS(err); + + memset(pData, 0xCADECADE, static_cast<size_t>(mem_reqs.size)); + + vkUnmapMemory(m_device->device(), mem); + + err = vkBindBufferMemory(m_device->device(), buffer, mem, 0); + ASSERT_VK_SUCCESS(err); + + // NOW, destroy the buffer. Obviously, the resource no longer occupies this + // memory. In fact, it was never used by the GPU. + // Just be be sure, wait for idle. + vkDestroyBuffer(m_device->device(), buffer, NULL); + vkDeviceWaitIdle(m_device->device()); + + VkImageCreateInfo image_create_info = {}; + image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + image_create_info.pNext = NULL; + image_create_info.imageType = VK_IMAGE_TYPE_2D; + image_create_info.format = VK_FORMAT_R8G8B8A8_UNORM; + image_create_info.extent.width = 64; + image_create_info.extent.height = 64; + image_create_info.extent.depth = 1; + image_create_info.mipLevels = 1; + image_create_info.arrayLayers = 1; + image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; + image_create_info.tiling = VK_IMAGE_TILING_LINEAR; + image_create_info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; + image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + image_create_info.queueFamilyIndexCount = 0; + image_create_info.pQueueFamilyIndices = NULL; + image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + image_create_info.flags = 0; + + VkMemoryAllocateInfo mem_alloc = {}; + mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + mem_alloc.pNext = NULL; + mem_alloc.allocationSize = 0; + mem_alloc.memoryTypeIndex = 0; + + /* Create a mappable image. It will be the texture if linear images are ok + * to be textures or it will be the staging image if they are not. + */ + err = vkCreateImage(m_device->device(), &image_create_info, NULL, &image); + ASSERT_VK_SUCCESS(err); + + vkGetImageMemoryRequirements(m_device->device(), image, &mem_reqs); + + mem_alloc.allocationSize = mem_reqs.size; + + pass = m_device->phy().set_memory_type(mem_reqs.memoryTypeBits, &mem_alloc, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); + if (!pass) { + vkDestroyImage(m_device->device(), image, NULL); + return; + } + + // VALIDATION FAILURE: + err = vkBindImageMemory(m_device->device(), image, mem, 0); + ASSERT_VK_SUCCESS(err); + + m_errorMonitor->VerifyNotFound(); + + vkFreeMemory(m_device->device(), mem, NULL); + vkDestroyBuffer(m_device->device(), buffer, NULL); + vkDestroyImage(m_device->device(), image, NULL); +} + +TEST_F(VkPositiveLayerTest, NonCoherentMemoryMapping) { + + TEST_DESCRIPTION("Ensure that validations handling of non-coherent memory " + "mapping while using VK_WHOLE_SIZE does not cause access " + "violations"); + VkResult err; + uint8_t *pData; + ASSERT_NO_FATAL_FAILURE(InitState()); + + VkDeviceMemory mem; + VkMemoryRequirements mem_reqs; + mem_reqs.memoryTypeBits = 0xFFFFFFFF; + VkMemoryAllocateInfo alloc_info = {}; + alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + alloc_info.pNext = NULL; + alloc_info.memoryTypeIndex = 0; + + static const VkDeviceSize allocation_size = 0x1000; + alloc_info.allocationSize = allocation_size; + + // Find a memory configurations WITHOUT a COHERENT bit, otherwise exit + bool pass = m_device->phy().set_memory_type(mem_reqs.memoryTypeBits, &alloc_info, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + if (!pass) { + pass = m_device->phy().set_memory_type(mem_reqs.memoryTypeBits, &alloc_info, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + if (!pass) { + pass = m_device->phy().set_memory_type(mem_reqs.memoryTypeBits, &alloc_info, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | + VK_MEMORY_PROPERTY_HOST_CACHED_BIT, + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + if (!pass) { + return; + } + } + } + + err = vkAllocateMemory(m_device->device(), &alloc_info, NULL, &mem); + ASSERT_VK_SUCCESS(err); + + // Map/Flush/Invalidate using WHOLE_SIZE and zero offsets and entire + // mapped range + m_errorMonitor->ExpectSuccess(); + err = vkMapMemory(m_device->device(), mem, 0, VK_WHOLE_SIZE, 0, (void **)&pData); + ASSERT_VK_SUCCESS(err); + VkMappedMemoryRange mmr = {}; + mmr.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; + mmr.memory = mem; + mmr.offset = 0; + mmr.size = VK_WHOLE_SIZE; + err = vkFlushMappedMemoryRanges(m_device->device(), 1, &mmr); + ASSERT_VK_SUCCESS(err); + err = vkInvalidateMappedMemoryRanges(m_device->device(), 1, &mmr); + ASSERT_VK_SUCCESS(err); + m_errorMonitor->VerifyNotFound(); + vkUnmapMemory(m_device->device(), mem); + + // Map/Flush/Invalidate using WHOLE_SIZE and a prime offset and entire + // mapped range + m_errorMonitor->ExpectSuccess(); + err = vkMapMemory(m_device->device(), mem, 13, VK_WHOLE_SIZE, 0, (void **)&pData); + ASSERT_VK_SUCCESS(err); + mmr.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; + mmr.memory = mem; + mmr.offset = 13; + mmr.size = VK_WHOLE_SIZE; + err = vkFlushMappedMemoryRanges(m_device->device(), 1, &mmr); + ASSERT_VK_SUCCESS(err); + err = vkInvalidateMappedMemoryRanges(m_device->device(), 1, &mmr); + ASSERT_VK_SUCCESS(err); + m_errorMonitor->VerifyNotFound(); + vkUnmapMemory(m_device->device(), mem); + + // Map with prime offset and size + // Flush/Invalidate subrange of mapped area with prime offset and size + m_errorMonitor->ExpectSuccess(); + err = vkMapMemory(m_device->device(), mem, allocation_size - 137, 109, 0, (void **)&pData); + ASSERT_VK_SUCCESS(err); + mmr.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; + mmr.memory = mem; + mmr.offset = allocation_size - 107; + mmr.size = 61; + err = vkFlushMappedMemoryRanges(m_device->device(), 1, &mmr); + ASSERT_VK_SUCCESS(err); + err = vkInvalidateMappedMemoryRanges(m_device->device(), 1, &mmr); + ASSERT_VK_SUCCESS(err); + m_errorMonitor->VerifyNotFound(); + vkUnmapMemory(m_device->device(), mem); + + // Map without offset and flush WHOLE_SIZE with two separate offsets + m_errorMonitor->ExpectSuccess(); + err = vkMapMemory(m_device->device(), mem, 0, VK_WHOLE_SIZE, 0, (void **)&pData); + ASSERT_VK_SUCCESS(err); + mmr.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; + mmr.memory = mem; + mmr.offset = allocation_size - 100; + mmr.size = VK_WHOLE_SIZE; + err = vkFlushMappedMemoryRanges(m_device->device(), 1, &mmr); + ASSERT_VK_SUCCESS(err); + mmr.offset = allocation_size - 200; + mmr.size = VK_WHOLE_SIZE; + err = vkFlushMappedMemoryRanges(m_device->device(), 1, &mmr); + ASSERT_VK_SUCCESS(err); + m_errorMonitor->VerifyNotFound(); + vkUnmapMemory(m_device->device(), mem); + + vkFreeMemory(m_device->device(), mem, NULL); +} + +// This is a positive test. We used to expect error in this case but spec now allows it +TEST_F(VkPositiveLayerTest, ResetUnsignaledFence) { + m_errorMonitor->ExpectSuccess(); + vk_testing::Fence testFence; + VkFenceCreateInfo fenceInfo = {}; + fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fenceInfo.pNext = NULL; + + ASSERT_NO_FATAL_FAILURE(InitState()); + testFence.init(*m_device, fenceInfo); + VkFence fences[1] = { testFence.handle() }; + VkResult result = vkResetFences(m_device->device(), 1, fences); + ASSERT_VK_SUCCESS(result); + + m_errorMonitor->VerifyNotFound(); +} + +TEST_F(VkPositiveLayerTest, CommandBufferSimultaneousUseSync) { + m_errorMonitor->ExpectSuccess(); + + ASSERT_NO_FATAL_FAILURE(InitState()); + VkResult err; + + // Record (empty!) command buffer that can be submitted multiple times + // simultaneously. + VkCommandBufferBeginInfo cbbi = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, nullptr, + VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, nullptr }; + m_commandBuffer->BeginCommandBuffer(&cbbi); + m_commandBuffer->EndCommandBuffer(); + + VkFenceCreateInfo fci = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr, 0 }; + VkFence fence; + err = vkCreateFence(m_device->device(), &fci, nullptr, &fence); + ASSERT_VK_SUCCESS(err); + + VkSemaphoreCreateInfo sci = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, nullptr, 0 }; + VkSemaphore s1, s2; + err = vkCreateSemaphore(m_device->device(), &sci, nullptr, &s1); + ASSERT_VK_SUCCESS(err); + err = vkCreateSemaphore(m_device->device(), &sci, nullptr, &s2); + ASSERT_VK_SUCCESS(err); + + // Submit CB once signaling s1, with fence so we can roll forward to its retirement. + VkSubmitInfo si = { VK_STRUCTURE_TYPE_SUBMIT_INFO, nullptr, 0, nullptr, nullptr, 1, &m_commandBuffer->handle(), 1, &s1 }; + err = vkQueueSubmit(m_device->m_queue, 1, &si, fence); + ASSERT_VK_SUCCESS(err); + + // Submit CB again, signaling s2. + si.pSignalSemaphores = &s2; + err = vkQueueSubmit(m_device->m_queue, 1, &si, VK_NULL_HANDLE); + ASSERT_VK_SUCCESS(err); + + // Wait for fence. + err = vkWaitForFences(m_device->device(), 1, &fence, VK_TRUE, UINT64_MAX); + ASSERT_VK_SUCCESS(err); + + // CB is still in flight from second submission, but semaphore s1 is no + // longer in flight. delete it. + vkDestroySemaphore(m_device->device(), s1, nullptr); + + m_errorMonitor->VerifyNotFound(); + + // Force device idle and clean up remaining objects + vkDeviceWaitIdle(m_device->device()); + vkDestroySemaphore(m_device->device(), s2, nullptr); + vkDestroyFence(m_device->device(), fence, nullptr); +} + +TEST_F(VkPositiveLayerTest, FenceCreateSignaledWaitHandling) { + m_errorMonitor->ExpectSuccess(); + + ASSERT_NO_FATAL_FAILURE(InitState()); + VkResult err; + + // A fence created signaled + VkFenceCreateInfo fci1 = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr, VK_FENCE_CREATE_SIGNALED_BIT }; + VkFence f1; + err = vkCreateFence(m_device->device(), &fci1, nullptr, &f1); + ASSERT_VK_SUCCESS(err); + + // A fence created not + VkFenceCreateInfo fci2 = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr, 0 }; + VkFence f2; + err = vkCreateFence(m_device->device(), &fci2, nullptr, &f2); + ASSERT_VK_SUCCESS(err); + + // Submit the unsignaled fence + VkSubmitInfo si = { VK_STRUCTURE_TYPE_SUBMIT_INFO, nullptr, 0, nullptr, nullptr, 0, nullptr, 0, nullptr }; + err = vkQueueSubmit(m_device->m_queue, 1, &si, f2); + + // Wait on both fences, with signaled first. + VkFence fences[] = { f1, f2 }; + vkWaitForFences(m_device->device(), 2, fences, VK_TRUE, UINT64_MAX); + + // Should have both retired! + vkDestroyFence(m_device->device(), f1, nullptr); + vkDestroyFence(m_device->device(), f2, nullptr); + + m_errorMonitor->VerifyNotFound(); +} + +TEST_F(VkPositiveLayerTest, ValidUsage) { + TEST_DESCRIPTION("Verify that creating an image view from an image with valid usage " + "doesn't generate validation errors"); + + ASSERT_NO_FATAL_FAILURE(InitState()); + + m_errorMonitor->ExpectSuccess(); + // Verify that we can create a view with usage INPUT_ATTACHMENT + VkImageObj image(m_device); + image.init(128, 128, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, VK_IMAGE_TILING_OPTIMAL, 0); + ASSERT_TRUE(image.initialized()); + VkImageView imageView; + VkImageViewCreateInfo ivci = {}; + ivci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + ivci.image = image.handle(); + ivci.viewType = VK_IMAGE_VIEW_TYPE_2D; + ivci.format = VK_FORMAT_R8G8B8A8_UNORM; + ivci.subresourceRange.layerCount = 1; + ivci.subresourceRange.baseMipLevel = 0; + ivci.subresourceRange.levelCount = 1; + ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + + vkCreateImageView(m_device->device(), &ivci, NULL, &imageView); + m_errorMonitor->VerifyNotFound(); + vkDestroyImageView(m_device->device(), imageView, NULL); +} + +// This is a positive test. No failures are expected. +TEST_F(VkPositiveLayerTest, BindSparse) { + TEST_DESCRIPTION("Bind 2 memory ranges to one image using vkQueueBindSparse, destroy the image" + "and then free the memory"); + + ASSERT_NO_FATAL_FAILURE(InitState()); + + auto index = m_device->graphics_queue_node_index_; + if (!(m_device->queue_props[index].queueFlags & VK_QUEUE_SPARSE_BINDING_BIT)) + return; + + m_errorMonitor->ExpectSuccess(); + + VkImage image; + VkImageCreateInfo image_create_info = {}; + image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + image_create_info.pNext = NULL; + image_create_info.imageType = VK_IMAGE_TYPE_2D; + image_create_info.format = VK_FORMAT_B8G8R8A8_UNORM; + image_create_info.extent.width = 64; + image_create_info.extent.height = 64; + image_create_info.extent.depth = 1; + image_create_info.mipLevels = 1; + image_create_info.arrayLayers = 1; + image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; + image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; + image_create_info.usage = VK_IMAGE_USAGE_STORAGE_BIT; + image_create_info.flags = VK_IMAGE_CREATE_SPARSE_BINDING_BIT; + VkResult err = vkCreateImage(m_device->device(), &image_create_info, NULL, &image); + ASSERT_VK_SUCCESS(err); + + VkMemoryRequirements memory_reqs; + VkDeviceMemory memory_one, memory_two; + bool pass; + VkMemoryAllocateInfo memory_info = {}; + memory_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + memory_info.pNext = NULL; + memory_info.allocationSize = 0; + memory_info.memoryTypeIndex = 0; + vkGetImageMemoryRequirements(m_device->device(), image, &memory_reqs); + // Find an image big enough to allow sparse mapping of 2 memory regions + // Increase the image size until it is at least twice the + // size of the required alignment, to ensure we can bind both + // allocated memory blocks to the image on aligned offsets. + while (memory_reqs.size < (memory_reqs.alignment * 2)) { + vkDestroyImage(m_device->device(), image, nullptr); + image_create_info.extent.width *= 2; + image_create_info.extent.height *= 2; + err = vkCreateImage(m_device->device(), &image_create_info, nullptr, &image); + ASSERT_VK_SUCCESS(err); + vkGetImageMemoryRequirements(m_device->device(), image, &memory_reqs); + } + // Allocate 2 memory regions of minimum alignment size, bind one at 0, the other + // at the end of the first + memory_info.allocationSize = memory_reqs.alignment; + pass = m_device->phy().set_memory_type(memory_reqs.memoryTypeBits, &memory_info, 0); + ASSERT_TRUE(pass); + err = vkAllocateMemory(m_device->device(), &memory_info, NULL, &memory_one); + ASSERT_VK_SUCCESS(err); + err = vkAllocateMemory(m_device->device(), &memory_info, NULL, &memory_two); + ASSERT_VK_SUCCESS(err); + VkSparseMemoryBind binds[2]; + binds[0].flags = 0; + binds[0].memory = memory_one; + binds[0].memoryOffset = 0; + binds[0].resourceOffset = 0; + binds[0].size = memory_info.allocationSize; + binds[1].flags = 0; + binds[1].memory = memory_two; + binds[1].memoryOffset = 0; + binds[1].resourceOffset = memory_info.allocationSize; + binds[1].size = memory_info.allocationSize; + + VkSparseImageOpaqueMemoryBindInfo opaqueBindInfo; + opaqueBindInfo.image = image; + opaqueBindInfo.bindCount = 2; + opaqueBindInfo.pBinds = binds; + + VkFence fence = VK_NULL_HANDLE; + VkBindSparseInfo bindSparseInfo = {}; + bindSparseInfo.sType = VK_STRUCTURE_TYPE_BIND_SPARSE_INFO; + bindSparseInfo.imageOpaqueBindCount = 1; + bindSparseInfo.pImageOpaqueBinds = &opaqueBindInfo; + + vkQueueBindSparse(m_device->m_queue, 1, &bindSparseInfo, fence); + vkQueueWaitIdle(m_device->m_queue); + vkDestroyImage(m_device->device(), image, NULL); + vkFreeMemory(m_device->device(), memory_one, NULL); + vkFreeMemory(m_device->device(), memory_two, NULL); + m_errorMonitor->VerifyNotFound(); +} + +TEST_F(VkPositiveLayerTest, RenderPassInitialLayoutUndefined) { + TEST_DESCRIPTION("Ensure that CmdBeginRenderPass with an attachment's " + "initialLayout of VK_IMAGE_LAYOUT_UNDEFINED works when " + "the command buffer has prior knowledge of that " + "attachment's layout."); + + m_errorMonitor->ExpectSuccess(); + + ASSERT_NO_FATAL_FAILURE(InitState()); + + // A renderpass with one color attachment. + VkAttachmentDescription attachment = { 0, + VK_FORMAT_R8G8B8A8_UNORM, + VK_SAMPLE_COUNT_1_BIT, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, + VK_ATTACHMENT_STORE_OP_STORE, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, + VK_ATTACHMENT_STORE_OP_DONT_CARE, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; + + VkAttachmentReference att_ref = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; + + VkSubpassDescription subpass = { 0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 1, &att_ref, nullptr, nullptr, 0, nullptr }; + + VkRenderPassCreateInfo rpci = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 1, &attachment, 1, &subpass, 0, nullptr }; + + VkRenderPass rp; + VkResult err = vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); + ASSERT_VK_SUCCESS(err); + + // A compatible framebuffer. + VkImageObj image(m_device); + image.init(32, 32, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_TILING_OPTIMAL, 0); + ASSERT_TRUE(image.initialized()); + + VkImageViewCreateInfo ivci = { + VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + nullptr, + 0, + image.handle(), + VK_IMAGE_VIEW_TYPE_2D, + VK_FORMAT_R8G8B8A8_UNORM, + { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_IDENTITY }, + { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }, + }; + VkImageView view; + err = vkCreateImageView(m_device->device(), &ivci, nullptr, &view); + ASSERT_VK_SUCCESS(err); + + VkFramebufferCreateInfo fci = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, nullptr, 0, rp, 1, &view, 32, 32, 1 }; + VkFramebuffer fb; + err = vkCreateFramebuffer(m_device->device(), &fci, nullptr, &fb); + ASSERT_VK_SUCCESS(err); + + // Record a single command buffer which uses this renderpass twice. The + // bug is triggered at the beginning of the second renderpass, when the + // command buffer already has a layout recorded for the attachment. + VkRenderPassBeginInfo rpbi = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, nullptr, rp, fb,{ { 0, 0 },{ 32, 32 } }, 0, nullptr }; + BeginCommandBuffer(); + vkCmdBeginRenderPass(m_commandBuffer->handle(), &rpbi, VK_SUBPASS_CONTENTS_INLINE); + vkCmdEndRenderPass(m_commandBuffer->handle()); + vkCmdBeginRenderPass(m_commandBuffer->handle(), &rpbi, VK_SUBPASS_CONTENTS_INLINE); + + m_errorMonitor->VerifyNotFound(); + + vkCmdEndRenderPass(m_commandBuffer->handle()); + EndCommandBuffer(); + + vkDestroyFramebuffer(m_device->device(), fb, nullptr); + vkDestroyRenderPass(m_device->device(), rp, nullptr); + vkDestroyImageView(m_device->device(), view, nullptr); +} + +TEST_F(VkPositiveLayerTest, FramebufferBindingDestroyCommandPool) { + TEST_DESCRIPTION("This test should pass. Create a Framebuffer and " + "command buffer, bind them together, then destroy " + "command pool and framebuffer and verify there are no " + "errors."); + + m_errorMonitor->ExpectSuccess(); + + ASSERT_NO_FATAL_FAILURE(InitState()); + + // A renderpass with one color attachment. + VkAttachmentDescription attachment = { 0, + VK_FORMAT_R8G8B8A8_UNORM, + VK_SAMPLE_COUNT_1_BIT, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, + VK_ATTACHMENT_STORE_OP_STORE, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, + VK_ATTACHMENT_STORE_OP_DONT_CARE, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; + + VkAttachmentReference att_ref = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; + + VkSubpassDescription subpass = { 0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 1, &att_ref, nullptr, nullptr, 0, nullptr }; + + VkRenderPassCreateInfo rpci = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 1, &attachment, 1, &subpass, 0, nullptr }; + + VkRenderPass rp; + VkResult err = vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); + ASSERT_VK_SUCCESS(err); + + // A compatible framebuffer. + VkImageObj image(m_device); + image.init(32, 32, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_TILING_OPTIMAL, 0); + ASSERT_TRUE(image.initialized()); + + VkImageViewCreateInfo ivci = { + VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + nullptr, + 0, + image.handle(), + VK_IMAGE_VIEW_TYPE_2D, + VK_FORMAT_R8G8B8A8_UNORM, + { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_IDENTITY }, + { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }, + }; + VkImageView view; + err = vkCreateImageView(m_device->device(), &ivci, nullptr, &view); + ASSERT_VK_SUCCESS(err); + + VkFramebufferCreateInfo fci = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, nullptr, 0, rp, 1, &view, 32, 32, 1 }; + VkFramebuffer fb; + err = vkCreateFramebuffer(m_device->device(), &fci, nullptr, &fb); + ASSERT_VK_SUCCESS(err); + + // Explicitly create a command buffer to bind the FB to so that we can then + // destroy the command pool in order to implicitly free command buffer + VkCommandPool command_pool; + VkCommandPoolCreateInfo pool_create_info{}; + pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_; + pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + vkCreateCommandPool(m_device->device(), &pool_create_info, nullptr, &command_pool); + + VkCommandBuffer command_buffer; + VkCommandBufferAllocateInfo command_buffer_allocate_info{}; + command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + command_buffer_allocate_info.commandPool = command_pool; + command_buffer_allocate_info.commandBufferCount = 1; + command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + vkAllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, &command_buffer); + + // Begin our cmd buffer with renderpass using our framebuffer + VkRenderPassBeginInfo rpbi = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, nullptr, rp, fb,{ { 0, 0 },{ 32, 32 } }, 0, nullptr }; + VkCommandBufferBeginInfo begin_info{}; + begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + vkBeginCommandBuffer(command_buffer, &begin_info); + + vkCmdBeginRenderPass(command_buffer, &rpbi, VK_SUBPASS_CONTENTS_INLINE); + vkCmdEndRenderPass(command_buffer); + vkEndCommandBuffer(command_buffer); + vkDestroyImageView(m_device->device(), view, nullptr); + // Destroy command pool to implicitly free command buffer + vkDestroyCommandPool(m_device->device(), command_pool, NULL); + vkDestroyFramebuffer(m_device->device(), fb, nullptr); + vkDestroyRenderPass(m_device->device(), rp, nullptr); + m_errorMonitor->VerifyNotFound(); +} + +TEST_F(VkPositiveLayerTest, RenderPassSubpassZeroTransitionsApplied) { + TEST_DESCRIPTION("Ensure that CmdBeginRenderPass applies the layout " + "transitions for the first subpass"); + + m_errorMonitor->ExpectSuccess(); + + ASSERT_NO_FATAL_FAILURE(InitState()); + + // A renderpass with one color attachment. + VkAttachmentDescription attachment = { 0, + VK_FORMAT_R8G8B8A8_UNORM, + VK_SAMPLE_COUNT_1_BIT, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, + VK_ATTACHMENT_STORE_OP_STORE, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, + VK_ATTACHMENT_STORE_OP_DONT_CARE, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; + + VkAttachmentReference att_ref = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; + + VkSubpassDescription subpass = { 0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 1, &att_ref, nullptr, nullptr, 0, nullptr }; + + VkSubpassDependency dep = { 0, + 0, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_DEPENDENCY_BY_REGION_BIT }; + + VkRenderPassCreateInfo rpci = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 1, &attachment, 1, &subpass, 1, &dep }; + + VkResult err; + VkRenderPass rp; + err = vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); + ASSERT_VK_SUCCESS(err); + + // A compatible framebuffer. + VkImageObj image(m_device); + image.init(32, 32, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_TILING_OPTIMAL, 0); + ASSERT_TRUE(image.initialized()); + + VkImageViewCreateInfo ivci = { + VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + nullptr, + 0, + image.handle(), + VK_IMAGE_VIEW_TYPE_2D, + VK_FORMAT_R8G8B8A8_UNORM, + { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_IDENTITY }, + { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }, + }; + VkImageView view; + err = vkCreateImageView(m_device->device(), &ivci, nullptr, &view); + ASSERT_VK_SUCCESS(err); + + VkFramebufferCreateInfo fci = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, nullptr, 0, rp, 1, &view, 32, 32, 1 }; + VkFramebuffer fb; + err = vkCreateFramebuffer(m_device->device(), &fci, nullptr, &fb); + ASSERT_VK_SUCCESS(err); + + // Record a single command buffer which issues a pipeline barrier w/ + // image memory barrier for the attachment. This detects the previously + // missing tracking of the subpass layout by throwing a validation error + // if it doesn't occur. + VkRenderPassBeginInfo rpbi = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, nullptr, rp, fb,{ { 0, 0 },{ 32, 32 } }, 0, nullptr }; + BeginCommandBuffer(); + vkCmdBeginRenderPass(m_commandBuffer->handle(), &rpbi, VK_SUBPASS_CONTENTS_INLINE); + + VkImageMemoryBarrier imb = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + nullptr, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_QUEUE_FAMILY_IGNORED, + VK_QUEUE_FAMILY_IGNORED, + image.handle(), + { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } }; + vkCmdPipelineBarrier(m_commandBuffer->handle(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_DEPENDENCY_BY_REGION_BIT, 0, nullptr, 0, nullptr, 1, + &imb); + + vkCmdEndRenderPass(m_commandBuffer->handle()); + m_errorMonitor->VerifyNotFound(); + EndCommandBuffer(); + + vkDestroyFramebuffer(m_device->device(), fb, nullptr); + vkDestroyRenderPass(m_device->device(), rp, nullptr); + vkDestroyImageView(m_device->device(), view, nullptr); +} + +TEST_F(VkPositiveLayerTest, DepthStencilLayoutTransitionForDepthOnlyImageview) { + TEST_DESCRIPTION("Validate that when an imageView of a depth/stencil image " + "is used as a depth/stencil framebuffer attachment, the " + "aspectMask is ignored and both depth and stencil image " + "subresources are used."); + + VkFormatProperties format_properties; + vkGetPhysicalDeviceFormatProperties(gpu(), VK_FORMAT_D32_SFLOAT_S8_UINT, &format_properties); + if (!(format_properties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) { + return; + } + + m_errorMonitor->ExpectSuccess(); + + ASSERT_NO_FATAL_FAILURE(InitState()); + + VkAttachmentDescription attachment = { 0, + VK_FORMAT_D32_SFLOAT_S8_UINT, + VK_SAMPLE_COUNT_1_BIT, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, + VK_ATTACHMENT_STORE_OP_STORE, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, + VK_ATTACHMENT_STORE_OP_DONT_CARE, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL }; + + VkAttachmentReference att_ref = { 0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL }; + + VkSubpassDescription subpass = { 0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 0, nullptr, nullptr, &att_ref, 0, nullptr }; + + VkSubpassDependency dep = { 0, + 0, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_DEPENDENCY_BY_REGION_BIT}; + + VkRenderPassCreateInfo rpci = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 1, &attachment, 1, &subpass, 1, &dep }; + + VkResult err; + VkRenderPass rp; + err = vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); + ASSERT_VK_SUCCESS(err); + + VkImageObj image(m_device); + image.init_no_layout(32, 32, VK_FORMAT_D32_SFLOAT_S8_UINT, + 0x26, // usage + VK_IMAGE_TILING_OPTIMAL, 0); + ASSERT_TRUE(image.initialized()); + image.SetLayout(0x6, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + + VkImageViewCreateInfo ivci = { + VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + nullptr, + 0, + image.handle(), + VK_IMAGE_VIEW_TYPE_2D, + VK_FORMAT_D32_SFLOAT_S8_UINT, + { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }, + { 0x2, 0, 1, 0, 1 }, + }; + VkImageView view; + err = vkCreateImageView(m_device->device(), &ivci, nullptr, &view); + ASSERT_VK_SUCCESS(err); + + VkFramebufferCreateInfo fci = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, nullptr, 0, rp, 1, &view, 32, 32, 1 }; + VkFramebuffer fb; + err = vkCreateFramebuffer(m_device->device(), &fci, nullptr, &fb); + ASSERT_VK_SUCCESS(err); + + VkRenderPassBeginInfo rpbi = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, nullptr, rp, fb,{ { 0, 0 },{ 32, 32 } }, 0, nullptr }; + BeginCommandBuffer(); + vkCmdBeginRenderPass(m_commandBuffer->handle(), &rpbi, VK_SUBPASS_CONTENTS_INLINE); + + VkImageMemoryBarrier imb = {}; + imb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + imb.pNext = nullptr; + imb.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + imb.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + imb.oldLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + imb.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + imb.srcQueueFamilyIndex = 0; + imb.dstQueueFamilyIndex = 0; + imb.image = image.handle(); + imb.subresourceRange.aspectMask = 0x6; + imb.subresourceRange.baseMipLevel = 0; + imb.subresourceRange.levelCount = 0x1; + imb.subresourceRange.baseArrayLayer = 0; + imb.subresourceRange.layerCount = 0x1; + + vkCmdPipelineBarrier(m_commandBuffer->handle(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_DEPENDENCY_BY_REGION_BIT, 0, nullptr, 0, nullptr, 1, + &imb); + + vkCmdEndRenderPass(m_commandBuffer->handle()); + EndCommandBuffer(); + QueueCommandBuffer(false); + m_errorMonitor->VerifyNotFound(); + + vkDestroyFramebuffer(m_device->device(), fb, nullptr); + vkDestroyRenderPass(m_device->device(), rp, nullptr); + vkDestroyImageView(m_device->device(), view, nullptr); +} + +TEST_F(VkPositiveLayerTest, RenderPassTransitionsAttachmentUnused) { + TEST_DESCRIPTION("Ensure that layout transitions work correctly without " + "errors, when an attachment reference is " + "VK_ATTACHMENT_UNUSED"); + + m_errorMonitor->ExpectSuccess(); + + ASSERT_NO_FATAL_FAILURE(InitState()); + + // A renderpass with no attachments + VkAttachmentReference att_ref = { VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; + + VkSubpassDescription subpass = { 0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 1, &att_ref, nullptr, nullptr, 0, nullptr }; + + VkRenderPassCreateInfo rpci = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 0, nullptr, 1, &subpass, 0, nullptr }; + + VkRenderPass rp; + VkResult err = vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); + ASSERT_VK_SUCCESS(err); + + // A compatible framebuffer. + VkFramebufferCreateInfo fci = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, nullptr, 0, rp, 0, nullptr, 32, 32, 1 }; + VkFramebuffer fb; + err = vkCreateFramebuffer(m_device->device(), &fci, nullptr, &fb); + ASSERT_VK_SUCCESS(err); + + // Record a command buffer which just begins and ends the renderpass. The + // bug manifests in BeginRenderPass. + VkRenderPassBeginInfo rpbi = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, nullptr, rp, fb,{ { 0, 0 },{ 32, 32 } }, 0, nullptr }; + BeginCommandBuffer(); + vkCmdBeginRenderPass(m_commandBuffer->handle(), &rpbi, VK_SUBPASS_CONTENTS_INLINE); + vkCmdEndRenderPass(m_commandBuffer->handle()); + m_errorMonitor->VerifyNotFound(); + EndCommandBuffer(); + + vkDestroyFramebuffer(m_device->device(), fb, nullptr); + vkDestroyRenderPass(m_device->device(), rp, nullptr); +} + +// This is a positive test. No errors are expected. +TEST_F(VkPositiveLayerTest, StencilLoadOp) { + TEST_DESCRIPTION("Create a stencil-only attachment with a LOAD_OP set to " + "CLEAR. stencil[Load|Store]Op used to be ignored."); + VkResult result = VK_SUCCESS; + VkImageFormatProperties formatProps; + vkGetPhysicalDeviceImageFormatProperties(gpu(), VK_FORMAT_D24_UNORM_S8_UINT, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 0, + &formatProps); + if (formatProps.maxExtent.width < 100 || formatProps.maxExtent.height < 100) { + return; + } + + ASSERT_NO_FATAL_FAILURE(InitState()); + VkFormat depth_stencil_fmt = VK_FORMAT_D24_UNORM_S8_UINT; + m_depthStencil->Init(m_device, 100, 100, depth_stencil_fmt, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT); + VkAttachmentDescription att = {}; + VkAttachmentReference ref = {}; + att.format = depth_stencil_fmt; + att.samples = VK_SAMPLE_COUNT_1_BIT; + att.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + att.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + att.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + att.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; + att.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + att.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + VkClearValue clear; + clear.depthStencil.depth = 1.0; + clear.depthStencil.stencil = 0; + ref.attachment = 0; + ref.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + VkSubpassDescription subpass = {}; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.flags = 0; + subpass.inputAttachmentCount = 0; + subpass.pInputAttachments = NULL; + subpass.colorAttachmentCount = 0; + subpass.pColorAttachments = NULL; + subpass.pResolveAttachments = NULL; + subpass.pDepthStencilAttachment = &ref; + subpass.preserveAttachmentCount = 0; + subpass.pPreserveAttachments = NULL; + + VkRenderPass rp; + VkRenderPassCreateInfo rp_info = {}; + rp_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + rp_info.attachmentCount = 1; + rp_info.pAttachments = &att; + rp_info.subpassCount = 1; + rp_info.pSubpasses = &subpass; + result = vkCreateRenderPass(device(), &rp_info, NULL, &rp); + ASSERT_VK_SUCCESS(result); + + VkImageView *depthView = m_depthStencil->BindInfo(); + VkFramebufferCreateInfo fb_info = {}; + fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + fb_info.pNext = NULL; + fb_info.renderPass = rp; + fb_info.attachmentCount = 1; + fb_info.pAttachments = depthView; + fb_info.width = 100; + fb_info.height = 100; + fb_info.layers = 1; + VkFramebuffer fb; + result = vkCreateFramebuffer(device(), &fb_info, NULL, &fb); + ASSERT_VK_SUCCESS(result); + + VkRenderPassBeginInfo rpbinfo = {}; + rpbinfo.clearValueCount = 1; + rpbinfo.pClearValues = &clear; + rpbinfo.pNext = NULL; + rpbinfo.renderPass = rp; + rpbinfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + rpbinfo.renderArea.extent.width = 100; + rpbinfo.renderArea.extent.height = 100; + rpbinfo.renderArea.offset.x = 0; + rpbinfo.renderArea.offset.y = 0; + rpbinfo.framebuffer = fb; + + VkFence fence = {}; + VkFenceCreateInfo fence_ci = {}; + fence_ci.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fence_ci.pNext = nullptr; + fence_ci.flags = 0; + result = vkCreateFence(m_device->device(), &fence_ci, nullptr, &fence); + ASSERT_VK_SUCCESS(result); + + m_commandBuffer->BeginCommandBuffer(); + m_commandBuffer->BeginRenderPass(rpbinfo); + m_commandBuffer->EndRenderPass(); + m_commandBuffer->EndCommandBuffer(); + m_commandBuffer->QueueCommandBuffer(fence); + + VkImageObj destImage(m_device); + destImage.init(100, 100, depth_stencil_fmt, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, + VK_IMAGE_TILING_OPTIMAL, 0); + VkImageMemoryBarrier barrier = {}; + VkImageSubresourceRange range; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; + barrier.oldLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + barrier.image = m_depthStencil->handle(); + range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + range.baseMipLevel = 0; + range.levelCount = 1; + range.baseArrayLayer = 0; + range.layerCount = 1; + barrier.subresourceRange = range; + vkWaitForFences(m_device->device(), 1, &fence, VK_TRUE, UINT64_MAX); + VkCommandBufferObj cmdbuf(m_device, m_commandPool); + cmdbuf.BeginCommandBuffer(); + cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, + &barrier); + barrier.srcAccessMask = 0; + barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + barrier.image = destImage.handle(); + barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, + &barrier); + VkImageCopy cregion; + cregion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + cregion.srcSubresource.mipLevel = 0; + cregion.srcSubresource.baseArrayLayer = 0; + cregion.srcSubresource.layerCount = 1; + cregion.srcOffset.x = 0; + cregion.srcOffset.y = 0; + cregion.srcOffset.z = 0; + cregion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + cregion.dstSubresource.mipLevel = 0; + cregion.dstSubresource.baseArrayLayer = 0; + cregion.dstSubresource.layerCount = 1; + cregion.dstOffset.x = 0; + cregion.dstOffset.y = 0; + cregion.dstOffset.z = 0; + cregion.extent.width = 100; + cregion.extent.height = 100; + cregion.extent.depth = 1; + cmdbuf.CopyImage(m_depthStencil->handle(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, destImage.handle(), + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &cregion); + cmdbuf.EndCommandBuffer(); + + VkSubmitInfo submit_info; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.pNext = NULL; + submit_info.waitSemaphoreCount = 0; + submit_info.pWaitSemaphores = NULL; + submit_info.pWaitDstStageMask = NULL; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &cmdbuf.handle(); + submit_info.signalSemaphoreCount = 0; + submit_info.pSignalSemaphores = NULL; + + m_errorMonitor->ExpectSuccess(); + vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); + m_errorMonitor->VerifyNotFound(); + + vkQueueWaitIdle(m_device->m_queue); + vkDestroyFence(m_device->device(), fence, nullptr); + vkDestroyRenderPass(m_device->device(), rp, nullptr); + vkDestroyFramebuffer(m_device->device(), fb, nullptr); +} + +// This is a positive test. No errors should be generated. +TEST_F(VkPositiveLayerTest, WaitEventThenSet) { + TEST_DESCRIPTION("Wait on a event then set it after the wait has been submitted."); + + m_errorMonitor->ExpectSuccess(); + ASSERT_NO_FATAL_FAILURE(InitState()); + + VkEvent event; + VkEventCreateInfo event_create_info{}; + event_create_info.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO; + vkCreateEvent(m_device->device(), &event_create_info, nullptr, &event); + + VkCommandPool command_pool; + VkCommandPoolCreateInfo pool_create_info{}; + pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_; + pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + vkCreateCommandPool(m_device->device(), &pool_create_info, nullptr, &command_pool); + + VkCommandBuffer command_buffer; + VkCommandBufferAllocateInfo command_buffer_allocate_info{}; + command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + command_buffer_allocate_info.commandPool = command_pool; + command_buffer_allocate_info.commandBufferCount = 1; + command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + vkAllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, &command_buffer); + + VkQueue queue = VK_NULL_HANDLE; + vkGetDeviceQueue(m_device->device(), m_device->graphics_queue_node_index_, 0, &queue); + + { + VkCommandBufferBeginInfo begin_info{}; + begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + vkBeginCommandBuffer(command_buffer, &begin_info); + + vkCmdWaitEvents(command_buffer, 1, &event, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, nullptr, 0, + nullptr, 0, nullptr); + vkCmdResetEvent(command_buffer, event, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); + vkEndCommandBuffer(command_buffer); + } + { + VkSubmitInfo submit_info{}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &command_buffer; + submit_info.signalSemaphoreCount = 0; + submit_info.pSignalSemaphores = nullptr; + vkQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE); + } + { vkSetEvent(m_device->device(), event); } + + vkQueueWaitIdle(queue); + + vkDestroyEvent(m_device->device(), event, nullptr); + vkFreeCommandBuffers(m_device->device(), command_pool, 1, &command_buffer); + vkDestroyCommandPool(m_device->device(), command_pool, NULL); + + m_errorMonitor->VerifyNotFound(); +} +// This is a positive test. No errors should be generated. +TEST_F(VkPositiveLayerTest, QueryAndCopySecondaryCommandBuffers) { + TEST_DESCRIPTION("Issue a query on a secondary command buffery and copy it on a primary."); + + ASSERT_NO_FATAL_FAILURE(InitState()); + if ((m_device->queue_props.empty()) || (m_device->queue_props[0].queueCount < 2)) + return; + + m_errorMonitor->ExpectSuccess(); + + VkQueryPool query_pool; + VkQueryPoolCreateInfo query_pool_create_info{}; + query_pool_create_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; + query_pool_create_info.queryType = VK_QUERY_TYPE_TIMESTAMP; + query_pool_create_info.queryCount = 1; + vkCreateQueryPool(m_device->device(), &query_pool_create_info, nullptr, &query_pool); + + VkCommandPool command_pool; + VkCommandPoolCreateInfo pool_create_info{}; + pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_; + pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + vkCreateCommandPool(m_device->device(), &pool_create_info, nullptr, &command_pool); + + VkCommandBuffer command_buffer; + VkCommandBufferAllocateInfo command_buffer_allocate_info{}; + command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + command_buffer_allocate_info.commandPool = command_pool; + command_buffer_allocate_info.commandBufferCount = 1; + command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + vkAllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, &command_buffer); + + VkCommandBuffer secondary_command_buffer; + command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY; + vkAllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, &secondary_command_buffer); + + VkQueue queue = VK_NULL_HANDLE; + vkGetDeviceQueue(m_device->device(), m_device->graphics_queue_node_index_, 1, &queue); + + uint32_t qfi = 0; + VkBufferCreateInfo buff_create_info = {}; + buff_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buff_create_info.size = 1024; + buff_create_info.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT; + buff_create_info.queueFamilyIndexCount = 1; + buff_create_info.pQueueFamilyIndices = &qfi; + + VkResult err; + VkBuffer buffer; + err = vkCreateBuffer(m_device->device(), &buff_create_info, NULL, &buffer); + ASSERT_VK_SUCCESS(err); + VkMemoryAllocateInfo mem_alloc = {}; + mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + mem_alloc.pNext = NULL; + mem_alloc.allocationSize = 1024; + mem_alloc.memoryTypeIndex = 0; + + VkMemoryRequirements memReqs; + vkGetBufferMemoryRequirements(m_device->device(), buffer, &memReqs); + bool pass = m_device->phy().set_memory_type(memReqs.memoryTypeBits, &mem_alloc, 0); + if (!pass) { + vkDestroyBuffer(m_device->device(), buffer, NULL); + return; + } + + VkDeviceMemory mem; + err = vkAllocateMemory(m_device->device(), &mem_alloc, NULL, &mem); + ASSERT_VK_SUCCESS(err); + err = vkBindBufferMemory(m_device->device(), buffer, mem, 0); + ASSERT_VK_SUCCESS(err); + + VkCommandBufferInheritanceInfo hinfo = {}; + hinfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; + hinfo.renderPass = VK_NULL_HANDLE; + hinfo.subpass = 0; + hinfo.framebuffer = VK_NULL_HANDLE; + hinfo.occlusionQueryEnable = VK_FALSE; + hinfo.queryFlags = 0; + hinfo.pipelineStatistics = 0; + + { + VkCommandBufferBeginInfo begin_info{}; + begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + begin_info.pInheritanceInfo = &hinfo; + vkBeginCommandBuffer(secondary_command_buffer, &begin_info); + + vkCmdResetQueryPool(secondary_command_buffer, query_pool, 0, 1); + vkCmdWriteTimestamp(secondary_command_buffer, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, query_pool, 0); + + vkEndCommandBuffer(secondary_command_buffer); + + begin_info.pInheritanceInfo = nullptr; + vkBeginCommandBuffer(command_buffer, &begin_info); + + vkCmdExecuteCommands(command_buffer, 1, &secondary_command_buffer); + vkCmdCopyQueryPoolResults(command_buffer, query_pool, 0, 1, buffer, 0, 0, 0); + + vkEndCommandBuffer(command_buffer); + } + { + VkSubmitInfo submit_info{}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &command_buffer; + submit_info.signalSemaphoreCount = 0; + submit_info.pSignalSemaphores = nullptr; + vkQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE); + } + + vkQueueWaitIdle(queue); + + vkDestroyQueryPool(m_device->device(), query_pool, nullptr); + vkFreeCommandBuffers(m_device->device(), command_pool, 1, &command_buffer); + vkFreeCommandBuffers(m_device->device(), command_pool, 1, &secondary_command_buffer); + vkDestroyCommandPool(m_device->device(), command_pool, NULL); + vkDestroyBuffer(m_device->device(), buffer, NULL); + vkFreeMemory(m_device->device(), mem, NULL); + + m_errorMonitor->VerifyNotFound(); +} + +// This is a positive test. No errors should be generated. +TEST_F(VkPositiveLayerTest, QueryAndCopyMultipleCommandBuffers) { + TEST_DESCRIPTION("Issue a query and copy from it on a second command buffer."); + + ASSERT_NO_FATAL_FAILURE(InitState()); + if ((m_device->queue_props.empty()) || (m_device->queue_props[0].queueCount < 2)) + return; + + m_errorMonitor->ExpectSuccess(); + + VkQueryPool query_pool; + VkQueryPoolCreateInfo query_pool_create_info{}; + query_pool_create_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; + query_pool_create_info.queryType = VK_QUERY_TYPE_TIMESTAMP; + query_pool_create_info.queryCount = 1; + vkCreateQueryPool(m_device->device(), &query_pool_create_info, nullptr, &query_pool); + + VkCommandPool command_pool; + VkCommandPoolCreateInfo pool_create_info{}; + pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_; + pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + vkCreateCommandPool(m_device->device(), &pool_create_info, nullptr, &command_pool); + + VkCommandBuffer command_buffer[2]; + VkCommandBufferAllocateInfo command_buffer_allocate_info{}; + command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + command_buffer_allocate_info.commandPool = command_pool; + command_buffer_allocate_info.commandBufferCount = 2; + command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + vkAllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, command_buffer); + + VkQueue queue = VK_NULL_HANDLE; + vkGetDeviceQueue(m_device->device(), m_device->graphics_queue_node_index_, 1, &queue); + + uint32_t qfi = 0; + VkBufferCreateInfo buff_create_info = {}; + buff_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buff_create_info.size = 1024; + buff_create_info.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT; + buff_create_info.queueFamilyIndexCount = 1; + buff_create_info.pQueueFamilyIndices = &qfi; + + VkResult err; + VkBuffer buffer; + err = vkCreateBuffer(m_device->device(), &buff_create_info, NULL, &buffer); + ASSERT_VK_SUCCESS(err); + VkMemoryAllocateInfo mem_alloc = {}; + mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + mem_alloc.pNext = NULL; + mem_alloc.allocationSize = 1024; + mem_alloc.memoryTypeIndex = 0; + + VkMemoryRequirements memReqs; + vkGetBufferMemoryRequirements(m_device->device(), buffer, &memReqs); + bool pass = m_device->phy().set_memory_type(memReqs.memoryTypeBits, &mem_alloc, 0); + if (!pass) { + vkDestroyBuffer(m_device->device(), buffer, NULL); + return; + } + + VkDeviceMemory mem; + err = vkAllocateMemory(m_device->device(), &mem_alloc, NULL, &mem); + ASSERT_VK_SUCCESS(err); + err = vkBindBufferMemory(m_device->device(), buffer, mem, 0); + ASSERT_VK_SUCCESS(err); + + { + VkCommandBufferBeginInfo begin_info{}; + begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + vkBeginCommandBuffer(command_buffer[0], &begin_info); + + vkCmdResetQueryPool(command_buffer[0], query_pool, 0, 1); + vkCmdWriteTimestamp(command_buffer[0], VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, query_pool, 0); + + vkEndCommandBuffer(command_buffer[0]); + + vkBeginCommandBuffer(command_buffer[1], &begin_info); + + vkCmdCopyQueryPoolResults(command_buffer[1], query_pool, 0, 1, buffer, 0, 0, 0); + + vkEndCommandBuffer(command_buffer[1]); + } + { + VkSubmitInfo submit_info{}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 2; + submit_info.pCommandBuffers = command_buffer; + submit_info.signalSemaphoreCount = 0; + submit_info.pSignalSemaphores = nullptr; + vkQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE); + } + + vkQueueWaitIdle(queue); + + vkDestroyQueryPool(m_device->device(), query_pool, nullptr); + vkFreeCommandBuffers(m_device->device(), command_pool, 2, command_buffer); + vkDestroyCommandPool(m_device->device(), command_pool, NULL); + vkDestroyBuffer(m_device->device(), buffer, NULL); + vkFreeMemory(m_device->device(), mem, NULL); + + m_errorMonitor->VerifyNotFound(); +} + +TEST_F(VkPositiveLayerTest, ResetEventThenSet) { + TEST_DESCRIPTION("Reset an event then set it after the reset has been submitted."); + + m_errorMonitor->ExpectSuccess(); + + ASSERT_NO_FATAL_FAILURE(InitState()); + VkEvent event; + VkEventCreateInfo event_create_info{}; + event_create_info.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO; + vkCreateEvent(m_device->device(), &event_create_info, nullptr, &event); + + VkCommandPool command_pool; + VkCommandPoolCreateInfo pool_create_info{}; + pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_; + pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + vkCreateCommandPool(m_device->device(), &pool_create_info, nullptr, &command_pool); + + VkCommandBuffer command_buffer; + VkCommandBufferAllocateInfo command_buffer_allocate_info{}; + command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + command_buffer_allocate_info.commandPool = command_pool; + command_buffer_allocate_info.commandBufferCount = 1; + command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + vkAllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, &command_buffer); + + VkQueue queue = VK_NULL_HANDLE; + vkGetDeviceQueue(m_device->device(), m_device->graphics_queue_node_index_, 0, &queue); + + { + VkCommandBufferBeginInfo begin_info{}; + begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + vkBeginCommandBuffer(command_buffer, &begin_info); + + vkCmdResetEvent(command_buffer, event, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); + vkCmdWaitEvents(command_buffer, 1, &event, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, + nullptr, 0, nullptr, 0, nullptr); + vkEndCommandBuffer(command_buffer); + } + { + VkSubmitInfo submit_info{}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &command_buffer; + submit_info.signalSemaphoreCount = 0; + submit_info.pSignalSemaphores = nullptr; + vkQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE); + } + { + m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "that is already in use by a " + "command buffer."); + vkSetEvent(m_device->device(), event); + m_errorMonitor->VerifyFound(); + } + + vkQueueWaitIdle(queue); + + vkDestroyEvent(m_device->device(), event, nullptr); + vkFreeCommandBuffers(m_device->device(), command_pool, 1, &command_buffer); + vkDestroyCommandPool(m_device->device(), command_pool, NULL); +} + +// This is a positive test. No errors should be generated. +TEST_F(VkPositiveLayerTest, TwoFencesThreeFrames) { + TEST_DESCRIPTION("Two command buffers with two separate fences are each " + "run through a Submit & WaitForFences cycle 3 times. This " + "previously revealed a bug so running this positive test " + "to prevent a regression."); + m_errorMonitor->ExpectSuccess(); + + ASSERT_NO_FATAL_FAILURE(InitState()); + VkQueue queue = VK_NULL_HANDLE; + vkGetDeviceQueue(m_device->device(), m_device->graphics_queue_node_index_, 0, &queue); + + static const uint32_t NUM_OBJECTS = 2; + static const uint32_t NUM_FRAMES = 3; + VkCommandBuffer cmd_buffers[NUM_OBJECTS] = {}; + VkFence fences[NUM_OBJECTS] = {}; + + VkCommandPool cmd_pool; + VkCommandPoolCreateInfo cmd_pool_ci = {}; + cmd_pool_ci.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + cmd_pool_ci.queueFamilyIndex = m_device->graphics_queue_node_index_; + cmd_pool_ci.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + VkResult err = vkCreateCommandPool(m_device->device(), &cmd_pool_ci, nullptr, &cmd_pool); + ASSERT_VK_SUCCESS(err); + + VkCommandBufferAllocateInfo cmd_buf_info = {}; + cmd_buf_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + cmd_buf_info.commandPool = cmd_pool; + cmd_buf_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + cmd_buf_info.commandBufferCount = 1; + + VkFenceCreateInfo fence_ci = {}; + fence_ci.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fence_ci.pNext = nullptr; + fence_ci.flags = 0; + + for (uint32_t i = 0; i < NUM_OBJECTS; ++i) { + err = vkAllocateCommandBuffers(m_device->device(), &cmd_buf_info, &cmd_buffers[i]); + ASSERT_VK_SUCCESS(err); + err = vkCreateFence(m_device->device(), &fence_ci, nullptr, &fences[i]); + ASSERT_VK_SUCCESS(err); + } + + for (uint32_t frame = 0; frame < NUM_FRAMES; ++frame) { + for (uint32_t obj = 0; obj < NUM_OBJECTS; ++obj) { + // Create empty cmd buffer + VkCommandBufferBeginInfo cmdBufBeginDesc = {}; + cmdBufBeginDesc.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + + err = vkBeginCommandBuffer(cmd_buffers[obj], &cmdBufBeginDesc); + ASSERT_VK_SUCCESS(err); + err = vkEndCommandBuffer(cmd_buffers[obj]); + ASSERT_VK_SUCCESS(err); + + VkSubmitInfo submit_info = {}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &cmd_buffers[obj]; + // Submit cmd buffer and wait for fence + err = vkQueueSubmit(queue, 1, &submit_info, fences[obj]); + ASSERT_VK_SUCCESS(err); + err = vkWaitForFences(m_device->device(), 1, &fences[obj], VK_TRUE, UINT64_MAX); + ASSERT_VK_SUCCESS(err); + err = vkResetFences(m_device->device(), 1, &fences[obj]); + ASSERT_VK_SUCCESS(err); + } + } + m_errorMonitor->VerifyNotFound(); + vkDestroyCommandPool(m_device->device(), cmd_pool, NULL); + for (uint32_t i = 0; i < NUM_OBJECTS; ++i) { + vkDestroyFence(m_device->device(), fences[i], nullptr); + } +} +// This is a positive test. No errors should be generated. +TEST_F(VkPositiveLayerTest, TwoQueueSubmitsSeparateQueuesWithSemaphoreAndOneFenceQWI) { + + TEST_DESCRIPTION("Two command buffers, each in a separate QueueSubmit call " + "submitted on separate queues followed by a QueueWaitIdle."); + + ASSERT_NO_FATAL_FAILURE(InitState()); + if ((m_device->queue_props.empty()) || (m_device->queue_props[0].queueCount < 2)) + return; + + m_errorMonitor->ExpectSuccess(); + + VkSemaphore semaphore; + VkSemaphoreCreateInfo semaphore_create_info{}; + semaphore_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + vkCreateSemaphore(m_device->device(), &semaphore_create_info, nullptr, &semaphore); + + VkCommandPool command_pool; + VkCommandPoolCreateInfo pool_create_info{}; + pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_; + pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + vkCreateCommandPool(m_device->device(), &pool_create_info, nullptr, &command_pool); + + VkCommandBuffer command_buffer[2]; + VkCommandBufferAllocateInfo command_buffer_allocate_info{}; + command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + command_buffer_allocate_info.commandPool = command_pool; + command_buffer_allocate_info.commandBufferCount = 2; + command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + vkAllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, command_buffer); + + VkQueue queue = VK_NULL_HANDLE; + vkGetDeviceQueue(m_device->device(), m_device->graphics_queue_node_index_, 1, &queue); + + { + VkCommandBufferBeginInfo begin_info{}; + begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + vkBeginCommandBuffer(command_buffer[0], &begin_info); + + vkCmdPipelineBarrier(command_buffer[0], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, + nullptr, 0, nullptr, 0, nullptr); + + VkViewport viewport{}; + viewport.maxDepth = 1.0f; + viewport.minDepth = 0.0f; + viewport.width = 512; + viewport.height = 512; + viewport.x = 0; + viewport.y = 0; + vkCmdSetViewport(command_buffer[0], 0, 1, &viewport); + vkEndCommandBuffer(command_buffer[0]); + } + { + VkCommandBufferBeginInfo begin_info{}; + begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + vkBeginCommandBuffer(command_buffer[1], &begin_info); + + VkViewport viewport{}; + viewport.maxDepth = 1.0f; + viewport.minDepth = 0.0f; + viewport.width = 512; + viewport.height = 512; + viewport.x = 0; + viewport.y = 0; + vkCmdSetViewport(command_buffer[1], 0, 1, &viewport); + vkEndCommandBuffer(command_buffer[1]); + } + { + VkSubmitInfo submit_info{}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &command_buffer[0]; + submit_info.signalSemaphoreCount = 1; + submit_info.pSignalSemaphores = &semaphore; + vkQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE); + } + { + VkPipelineStageFlags flags[]{ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT }; + VkSubmitInfo submit_info{}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &command_buffer[1]; + submit_info.waitSemaphoreCount = 1; + submit_info.pWaitSemaphores = &semaphore; + submit_info.pWaitDstStageMask = flags; + vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); + } + + vkQueueWaitIdle(m_device->m_queue); + + vkDestroySemaphore(m_device->device(), semaphore, nullptr); + vkFreeCommandBuffers(m_device->device(), command_pool, 2, &command_buffer[0]); + vkDestroyCommandPool(m_device->device(), command_pool, NULL); + + m_errorMonitor->VerifyNotFound(); +} + +// This is a positive test. No errors should be generated. +TEST_F(VkPositiveLayerTest, TwoQueueSubmitsSeparateQueuesWithSemaphoreAndOneFenceQWIFence) { + + TEST_DESCRIPTION("Two command buffers, each in a separate QueueSubmit call " + "submitted on separate queues, the second having a fence" + "followed by a QueueWaitIdle."); + + ASSERT_NO_FATAL_FAILURE(InitState()); + if ((m_device->queue_props.empty()) || (m_device->queue_props[0].queueCount < 2)) + return; + + m_errorMonitor->ExpectSuccess(); + + VkFence fence; + VkFenceCreateInfo fence_create_info{}; + fence_create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + vkCreateFence(m_device->device(), &fence_create_info, nullptr, &fence); + + VkSemaphore semaphore; + VkSemaphoreCreateInfo semaphore_create_info{}; + semaphore_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + vkCreateSemaphore(m_device->device(), &semaphore_create_info, nullptr, &semaphore); + + VkCommandPool command_pool; + VkCommandPoolCreateInfo pool_create_info{}; + pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_; + pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + vkCreateCommandPool(m_device->device(), &pool_create_info, nullptr, &command_pool); + + VkCommandBuffer command_buffer[2]; + VkCommandBufferAllocateInfo command_buffer_allocate_info{}; + command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + command_buffer_allocate_info.commandPool = command_pool; + command_buffer_allocate_info.commandBufferCount = 2; + command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + vkAllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, command_buffer); + + VkQueue queue = VK_NULL_HANDLE; + vkGetDeviceQueue(m_device->device(), m_device->graphics_queue_node_index_, 1, &queue); + + { + VkCommandBufferBeginInfo begin_info{}; + begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + vkBeginCommandBuffer(command_buffer[0], &begin_info); + + vkCmdPipelineBarrier(command_buffer[0], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, + nullptr, 0, nullptr, 0, nullptr); + + VkViewport viewport{}; + viewport.maxDepth = 1.0f; + viewport.minDepth = 0.0f; + viewport.width = 512; + viewport.height = 512; + viewport.x = 0; + viewport.y = 0; + vkCmdSetViewport(command_buffer[0], 0, 1, &viewport); + vkEndCommandBuffer(command_buffer[0]); + } + { + VkCommandBufferBeginInfo begin_info{}; + begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + vkBeginCommandBuffer(command_buffer[1], &begin_info); + + VkViewport viewport{}; + viewport.maxDepth = 1.0f; + viewport.minDepth = 0.0f; + viewport.width = 512; + viewport.height = 512; + viewport.x = 0; + viewport.y = 0; + vkCmdSetViewport(command_buffer[1], 0, 1, &viewport); + vkEndCommandBuffer(command_buffer[1]); + } + { + VkSubmitInfo submit_info{}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &command_buffer[0]; + submit_info.signalSemaphoreCount = 1; + submit_info.pSignalSemaphores = &semaphore; + vkQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE); + } + { + VkPipelineStageFlags flags[]{ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT }; + VkSubmitInfo submit_info{}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &command_buffer[1]; + submit_info.waitSemaphoreCount = 1; + submit_info.pWaitSemaphores = &semaphore; + submit_info.pWaitDstStageMask = flags; + vkQueueSubmit(m_device->m_queue, 1, &submit_info, fence); + } + + vkQueueWaitIdle(m_device->m_queue); + + vkDestroyFence(m_device->device(), fence, nullptr); + vkDestroySemaphore(m_device->device(), semaphore, nullptr); + vkFreeCommandBuffers(m_device->device(), command_pool, 2, &command_buffer[0]); + vkDestroyCommandPool(m_device->device(), command_pool, NULL); + + m_errorMonitor->VerifyNotFound(); +} + +// This is a positive test. No errors should be generated. +TEST_F(VkPositiveLayerTest, TwoQueueSubmitsSeparateQueuesWithSemaphoreAndOneFenceTwoWFF) { + + TEST_DESCRIPTION("Two command buffers, each in a separate QueueSubmit call " + "submitted on separate queues, the second having a fence" + "followed by two consecutive WaitForFences calls on the same fence."); + + ASSERT_NO_FATAL_FAILURE(InitState()); + if ((m_device->queue_props.empty()) || (m_device->queue_props[0].queueCount < 2)) + return; + + m_errorMonitor->ExpectSuccess(); + + VkFence fence; + VkFenceCreateInfo fence_create_info{}; + fence_create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + vkCreateFence(m_device->device(), &fence_create_info, nullptr, &fence); + + VkSemaphore semaphore; + VkSemaphoreCreateInfo semaphore_create_info{}; + semaphore_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + vkCreateSemaphore(m_device->device(), &semaphore_create_info, nullptr, &semaphore); + + VkCommandPool command_pool; + VkCommandPoolCreateInfo pool_create_info{}; + pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_; + pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + vkCreateCommandPool(m_device->device(), &pool_create_info, nullptr, &command_pool); + + VkCommandBuffer command_buffer[2]; + VkCommandBufferAllocateInfo command_buffer_allocate_info{}; + command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + command_buffer_allocate_info.commandPool = command_pool; + command_buffer_allocate_info.commandBufferCount = 2; + command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + vkAllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, command_buffer); + + VkQueue queue = VK_NULL_HANDLE; + vkGetDeviceQueue(m_device->device(), m_device->graphics_queue_node_index_, 1, &queue); + + { + VkCommandBufferBeginInfo begin_info{}; + begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + vkBeginCommandBuffer(command_buffer[0], &begin_info); + + vkCmdPipelineBarrier(command_buffer[0], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, + nullptr, 0, nullptr, 0, nullptr); + + VkViewport viewport{}; + viewport.maxDepth = 1.0f; + viewport.minDepth = 0.0f; + viewport.width = 512; + viewport.height = 512; + viewport.x = 0; + viewport.y = 0; + vkCmdSetViewport(command_buffer[0], 0, 1, &viewport); + vkEndCommandBuffer(command_buffer[0]); + } + { + VkCommandBufferBeginInfo begin_info{}; + begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + vkBeginCommandBuffer(command_buffer[1], &begin_info); + + VkViewport viewport{}; + viewport.maxDepth = 1.0f; + viewport.minDepth = 0.0f; + viewport.width = 512; + viewport.height = 512; + viewport.x = 0; + viewport.y = 0; + vkCmdSetViewport(command_buffer[1], 0, 1, &viewport); + vkEndCommandBuffer(command_buffer[1]); + } + { + VkSubmitInfo submit_info{}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &command_buffer[0]; + submit_info.signalSemaphoreCount = 1; + submit_info.pSignalSemaphores = &semaphore; + vkQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE); + } + { + VkPipelineStageFlags flags[]{ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT }; + VkSubmitInfo submit_info{}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &command_buffer[1]; + submit_info.waitSemaphoreCount = 1; + submit_info.pWaitSemaphores = &semaphore; + submit_info.pWaitDstStageMask = flags; + vkQueueSubmit(m_device->m_queue, 1, &submit_info, fence); + } + + vkWaitForFences(m_device->device(), 1, &fence, VK_TRUE, UINT64_MAX); + vkWaitForFences(m_device->device(), 1, &fence, VK_TRUE, UINT64_MAX); + + vkDestroyFence(m_device->device(), fence, nullptr); + vkDestroySemaphore(m_device->device(), semaphore, nullptr); + vkFreeCommandBuffers(m_device->device(), command_pool, 2, &command_buffer[0]); + vkDestroyCommandPool(m_device->device(), command_pool, NULL); + + m_errorMonitor->VerifyNotFound(); +} + +TEST_F(VkPositiveLayerTest, TwoQueuesEnsureCorrectRetirementWithWorkStolen) { + + ASSERT_NO_FATAL_FAILURE(InitState()); + if ((m_device->queue_props.empty()) || (m_device->queue_props[0].queueCount < 2)) { + printf("Test requires two queues, skipping\n"); + return; + } + + VkResult err; + + m_errorMonitor->ExpectSuccess(); + + VkQueue q0 = m_device->m_queue; + VkQueue q1 = nullptr; + vkGetDeviceQueue(m_device->device(), m_device->graphics_queue_node_index_, 1, &q1); + ASSERT_NE(q1, nullptr); + + // An (empty) command buffer. We must have work in the first submission -- + // the layer treats unfenced work differently from fenced work. + VkCommandPoolCreateInfo cpci = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, nullptr, 0, 0 }; + VkCommandPool pool; + err = vkCreateCommandPool(m_device->device(), &cpci, nullptr, &pool); + ASSERT_VK_SUCCESS(err); + VkCommandBufferAllocateInfo cbai = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, nullptr, pool, + VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1 }; + VkCommandBuffer cb; + err = vkAllocateCommandBuffers(m_device->device(), &cbai, &cb); + ASSERT_VK_SUCCESS(err); + VkCommandBufferBeginInfo cbbi = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, nullptr, 0, nullptr }; + err = vkBeginCommandBuffer(cb, &cbbi); + ASSERT_VK_SUCCESS(err); + err = vkEndCommandBuffer(cb); + ASSERT_VK_SUCCESS(err); + + // A semaphore + VkSemaphoreCreateInfo sci = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, nullptr, 0 }; + VkSemaphore s; + err = vkCreateSemaphore(m_device->device(), &sci, nullptr, &s); + ASSERT_VK_SUCCESS(err); + + // First submission, to q0 + VkSubmitInfo s0 = { VK_STRUCTURE_TYPE_SUBMIT_INFO, nullptr, 0, nullptr, nullptr, 1, &cb, 1, &s }; + + err = vkQueueSubmit(q0, 1, &s0, VK_NULL_HANDLE); + ASSERT_VK_SUCCESS(err); + + // Second submission, to q1, waiting on s + VkFlags waitmask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; // doesn't really matter what this value is. + VkSubmitInfo s1 = { VK_STRUCTURE_TYPE_SUBMIT_INFO, nullptr, 1, &s, &waitmask, 0, nullptr, 0, nullptr }; + + err = vkQueueSubmit(q1, 1, &s1, VK_NULL_HANDLE); + ASSERT_VK_SUCCESS(err); + + // Wait for q0 idle + err = vkQueueWaitIdle(q0); + ASSERT_VK_SUCCESS(err); + + // Command buffer should have been completed (it was on q0); reset the pool. + vkFreeCommandBuffers(m_device->device(), pool, 1, &cb); + + m_errorMonitor->VerifyNotFound(); + + // Force device completely idle and clean up resources + vkDeviceWaitIdle(m_device->device()); + vkDestroyCommandPool(m_device->device(), pool, nullptr); + vkDestroySemaphore(m_device->device(), s, nullptr); +} + +// This is a positive test. No errors should be generated. +TEST_F(VkPositiveLayerTest, TwoQueueSubmitsSeparateQueuesWithSemaphoreAndOneFence) { + + TEST_DESCRIPTION("Two command buffers, each in a separate QueueSubmit call " + "submitted on separate queues, the second having a fence, " + "followed by a WaitForFences call."); + + ASSERT_NO_FATAL_FAILURE(InitState()); + if ((m_device->queue_props.empty()) || (m_device->queue_props[0].queueCount < 2)) + return; + + m_errorMonitor->ExpectSuccess(); + + ASSERT_NO_FATAL_FAILURE(InitState()); + VkFence fence; + VkFenceCreateInfo fence_create_info{}; + fence_create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + vkCreateFence(m_device->device(), &fence_create_info, nullptr, &fence); + + VkSemaphore semaphore; + VkSemaphoreCreateInfo semaphore_create_info{}; + semaphore_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + vkCreateSemaphore(m_device->device(), &semaphore_create_info, nullptr, &semaphore); + + VkCommandPool command_pool; + VkCommandPoolCreateInfo pool_create_info{}; + pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_; + pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + vkCreateCommandPool(m_device->device(), &pool_create_info, nullptr, &command_pool); + + VkCommandBuffer command_buffer[2]; + VkCommandBufferAllocateInfo command_buffer_allocate_info{}; + command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + command_buffer_allocate_info.commandPool = command_pool; + command_buffer_allocate_info.commandBufferCount = 2; + command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + vkAllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, command_buffer); + + VkQueue queue = VK_NULL_HANDLE; + vkGetDeviceQueue(m_device->device(), m_device->graphics_queue_node_index_, 1, &queue); + + { + VkCommandBufferBeginInfo begin_info{}; + begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + vkBeginCommandBuffer(command_buffer[0], &begin_info); + + vkCmdPipelineBarrier(command_buffer[0], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, + nullptr, 0, nullptr, 0, nullptr); + + VkViewport viewport{}; + viewport.maxDepth = 1.0f; + viewport.minDepth = 0.0f; + viewport.width = 512; + viewport.height = 512; + viewport.x = 0; + viewport.y = 0; + vkCmdSetViewport(command_buffer[0], 0, 1, &viewport); + vkEndCommandBuffer(command_buffer[0]); + } + { + VkCommandBufferBeginInfo begin_info{}; + begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + vkBeginCommandBuffer(command_buffer[1], &begin_info); + + VkViewport viewport{}; + viewport.maxDepth = 1.0f; + viewport.minDepth = 0.0f; + viewport.width = 512; + viewport.height = 512; + viewport.x = 0; + viewport.y = 0; + vkCmdSetViewport(command_buffer[1], 0, 1, &viewport); + vkEndCommandBuffer(command_buffer[1]); + } + { + VkSubmitInfo submit_info{}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &command_buffer[0]; + submit_info.signalSemaphoreCount = 1; + submit_info.pSignalSemaphores = &semaphore; + vkQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE); + } + { + VkPipelineStageFlags flags[]{ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT }; + VkSubmitInfo submit_info{}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &command_buffer[1]; + submit_info.waitSemaphoreCount = 1; + submit_info.pWaitSemaphores = &semaphore; + submit_info.pWaitDstStageMask = flags; + vkQueueSubmit(m_device->m_queue, 1, &submit_info, fence); + } + + vkWaitForFences(m_device->device(), 1, &fence, VK_TRUE, UINT64_MAX); + + vkDestroyFence(m_device->device(), fence, nullptr); + vkDestroySemaphore(m_device->device(), semaphore, nullptr); + vkFreeCommandBuffers(m_device->device(), command_pool, 2, &command_buffer[0]); + vkDestroyCommandPool(m_device->device(), command_pool, NULL); + + m_errorMonitor->VerifyNotFound(); +} + +// This is a positive test. No errors should be generated. +TEST_F(VkPositiveLayerTest, TwoQueueSubmitsOneQueueWithSemaphoreAndOneFence) { + + TEST_DESCRIPTION("Two command buffers, each in a separate QueueSubmit call " + "on the same queue, sharing a signal/wait semaphore, the " + "second having a fence, " + "followed by a WaitForFences call."); + + m_errorMonitor->ExpectSuccess(); + + ASSERT_NO_FATAL_FAILURE(InitState()); + VkFence fence; + VkFenceCreateInfo fence_create_info{}; + fence_create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + vkCreateFence(m_device->device(), &fence_create_info, nullptr, &fence); + + VkSemaphore semaphore; + VkSemaphoreCreateInfo semaphore_create_info{}; + semaphore_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + vkCreateSemaphore(m_device->device(), &semaphore_create_info, nullptr, &semaphore); + + VkCommandPool command_pool; + VkCommandPoolCreateInfo pool_create_info{}; + pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_; + pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + vkCreateCommandPool(m_device->device(), &pool_create_info, nullptr, &command_pool); + + VkCommandBuffer command_buffer[2]; + VkCommandBufferAllocateInfo command_buffer_allocate_info{}; + command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + command_buffer_allocate_info.commandPool = command_pool; + command_buffer_allocate_info.commandBufferCount = 2; + command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + vkAllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, command_buffer); + + { + VkCommandBufferBeginInfo begin_info{}; + begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + vkBeginCommandBuffer(command_buffer[0], &begin_info); + + vkCmdPipelineBarrier(command_buffer[0], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, + nullptr, 0, nullptr, 0, nullptr); + + VkViewport viewport{}; + viewport.maxDepth = 1.0f; + viewport.minDepth = 0.0f; + viewport.width = 512; + viewport.height = 512; + viewport.x = 0; + viewport.y = 0; + vkCmdSetViewport(command_buffer[0], 0, 1, &viewport); + vkEndCommandBuffer(command_buffer[0]); + } + { + VkCommandBufferBeginInfo begin_info{}; + begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + vkBeginCommandBuffer(command_buffer[1], &begin_info); + + VkViewport viewport{}; + viewport.maxDepth = 1.0f; + viewport.minDepth = 0.0f; + viewport.width = 512; + viewport.height = 512; + viewport.x = 0; + viewport.y = 0; + vkCmdSetViewport(command_buffer[1], 0, 1, &viewport); + vkEndCommandBuffer(command_buffer[1]); + } + { + VkSubmitInfo submit_info{}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &command_buffer[0]; + submit_info.signalSemaphoreCount = 1; + submit_info.pSignalSemaphores = &semaphore; + vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); + } + { + VkPipelineStageFlags flags[]{ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT }; + VkSubmitInfo submit_info{}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &command_buffer[1]; + submit_info.waitSemaphoreCount = 1; + submit_info.pWaitSemaphores = &semaphore; + submit_info.pWaitDstStageMask = flags; + vkQueueSubmit(m_device->m_queue, 1, &submit_info, fence); + } + + vkWaitForFences(m_device->device(), 1, &fence, VK_TRUE, UINT64_MAX); + + vkDestroyFence(m_device->device(), fence, nullptr); + vkDestroySemaphore(m_device->device(), semaphore, nullptr); + vkFreeCommandBuffers(m_device->device(), command_pool, 2, &command_buffer[0]); + vkDestroyCommandPool(m_device->device(), command_pool, NULL); + + m_errorMonitor->VerifyNotFound(); +} + +// This is a positive test. No errors should be generated. +TEST_F(VkPositiveLayerTest, TwoQueueSubmitsOneQueueNullQueueSubmitWithFence) { + + TEST_DESCRIPTION("Two command buffers, each in a separate QueueSubmit call " + "on the same queue, no fences, followed by a third QueueSubmit with NO " + "SubmitInfos but with a fence, followed by a WaitForFences call."); + + m_errorMonitor->ExpectSuccess(); + + ASSERT_NO_FATAL_FAILURE(InitState()); + VkFence fence; + VkFenceCreateInfo fence_create_info{}; + fence_create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + vkCreateFence(m_device->device(), &fence_create_info, nullptr, &fence); + + VkCommandPool command_pool; + VkCommandPoolCreateInfo pool_create_info{}; + pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_; + pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + vkCreateCommandPool(m_device->device(), &pool_create_info, nullptr, &command_pool); + + VkCommandBuffer command_buffer[2]; + VkCommandBufferAllocateInfo command_buffer_allocate_info{}; + command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + command_buffer_allocate_info.commandPool = command_pool; + command_buffer_allocate_info.commandBufferCount = 2; + command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + vkAllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, command_buffer); + + { + VkCommandBufferBeginInfo begin_info{}; + begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + vkBeginCommandBuffer(command_buffer[0], &begin_info); + + vkCmdPipelineBarrier(command_buffer[0], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, + nullptr, 0, nullptr, 0, nullptr); + + VkViewport viewport{}; + viewport.maxDepth = 1.0f; + viewport.minDepth = 0.0f; + viewport.width = 512; + viewport.height = 512; + viewport.x = 0; + viewport.y = 0; + vkCmdSetViewport(command_buffer[0], 0, 1, &viewport); + vkEndCommandBuffer(command_buffer[0]); + } + { + VkCommandBufferBeginInfo begin_info{}; + begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + vkBeginCommandBuffer(command_buffer[1], &begin_info); + + VkViewport viewport{}; + viewport.maxDepth = 1.0f; + viewport.minDepth = 0.0f; + viewport.width = 512; + viewport.height = 512; + viewport.x = 0; + viewport.y = 0; + vkCmdSetViewport(command_buffer[1], 0, 1, &viewport); + vkEndCommandBuffer(command_buffer[1]); + } + { + VkSubmitInfo submit_info{}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &command_buffer[0]; + submit_info.signalSemaphoreCount = 0; + submit_info.pSignalSemaphores = VK_NULL_HANDLE; + vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); + } + { + VkPipelineStageFlags flags[]{ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT }; + VkSubmitInfo submit_info{}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &command_buffer[1]; + submit_info.waitSemaphoreCount = 0; + submit_info.pWaitSemaphores = VK_NULL_HANDLE; + submit_info.pWaitDstStageMask = flags; + vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); + } + + vkQueueSubmit(m_device->m_queue, 0, NULL, fence); + + VkResult err = vkWaitForFences(m_device->device(), 1, &fence, VK_TRUE, UINT64_MAX); + ASSERT_VK_SUCCESS(err); + + vkDestroyFence(m_device->device(), fence, nullptr); + vkFreeCommandBuffers(m_device->device(), command_pool, 2, &command_buffer[0]); + vkDestroyCommandPool(m_device->device(), command_pool, NULL); + + m_errorMonitor->VerifyNotFound(); +} + +// This is a positive test. No errors should be generated. +TEST_F(VkPositiveLayerTest, TwoQueueSubmitsOneQueueOneFence) { + + TEST_DESCRIPTION("Two command buffers, each in a separate QueueSubmit call " + "on the same queue, the second having a fence, followed " + "by a WaitForFences call."); + + m_errorMonitor->ExpectSuccess(); + + ASSERT_NO_FATAL_FAILURE(InitState()); + VkFence fence; + VkFenceCreateInfo fence_create_info{}; + fence_create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + vkCreateFence(m_device->device(), &fence_create_info, nullptr, &fence); + + VkCommandPool command_pool; + VkCommandPoolCreateInfo pool_create_info{}; + pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_; + pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + vkCreateCommandPool(m_device->device(), &pool_create_info, nullptr, &command_pool); + + VkCommandBuffer command_buffer[2]; + VkCommandBufferAllocateInfo command_buffer_allocate_info{}; + command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + command_buffer_allocate_info.commandPool = command_pool; + command_buffer_allocate_info.commandBufferCount = 2; + command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + vkAllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, command_buffer); + + { + VkCommandBufferBeginInfo begin_info{}; + begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + vkBeginCommandBuffer(command_buffer[0], &begin_info); + + vkCmdPipelineBarrier(command_buffer[0], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, + nullptr, 0, nullptr, 0, nullptr); + + VkViewport viewport{}; + viewport.maxDepth = 1.0f; + viewport.minDepth = 0.0f; + viewport.width = 512; + viewport.height = 512; + viewport.x = 0; + viewport.y = 0; + vkCmdSetViewport(command_buffer[0], 0, 1, &viewport); + vkEndCommandBuffer(command_buffer[0]); + } + { + VkCommandBufferBeginInfo begin_info{}; + begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + vkBeginCommandBuffer(command_buffer[1], &begin_info); + + VkViewport viewport{}; + viewport.maxDepth = 1.0f; + viewport.minDepth = 0.0f; + viewport.width = 512; + viewport.height = 512; + viewport.x = 0; + viewport.y = 0; + vkCmdSetViewport(command_buffer[1], 0, 1, &viewport); + vkEndCommandBuffer(command_buffer[1]); + } + { + VkSubmitInfo submit_info{}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &command_buffer[0]; + submit_info.signalSemaphoreCount = 0; + submit_info.pSignalSemaphores = VK_NULL_HANDLE; + vkQueueSubmit(m_device->m_queue, 1, &submit_info, VK_NULL_HANDLE); + } + { + VkPipelineStageFlags flags[]{ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT }; + VkSubmitInfo submit_info{}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &command_buffer[1]; + submit_info.waitSemaphoreCount = 0; + submit_info.pWaitSemaphores = VK_NULL_HANDLE; + submit_info.pWaitDstStageMask = flags; + vkQueueSubmit(m_device->m_queue, 1, &submit_info, fence); + } + + vkWaitForFences(m_device->device(), 1, &fence, VK_TRUE, UINT64_MAX); + + vkDestroyFence(m_device->device(), fence, nullptr); + vkFreeCommandBuffers(m_device->device(), command_pool, 2, &command_buffer[0]); + vkDestroyCommandPool(m_device->device(), command_pool, NULL); + + m_errorMonitor->VerifyNotFound(); +} + +// This is a positive test. No errors should be generated. +TEST_F(VkPositiveLayerTest, TwoSubmitInfosWithSemaphoreOneQueueSubmitsOneFence) { + + TEST_DESCRIPTION("Two command buffers each in a separate SubmitInfo sent in a single " + "QueueSubmit call followed by a WaitForFences call."); + ASSERT_NO_FATAL_FAILURE(InitState()); + + m_errorMonitor->ExpectSuccess(); + + VkFence fence; + VkFenceCreateInfo fence_create_info{}; + fence_create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + vkCreateFence(m_device->device(), &fence_create_info, nullptr, &fence); + + VkSemaphore semaphore; + VkSemaphoreCreateInfo semaphore_create_info{}; + semaphore_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + vkCreateSemaphore(m_device->device(), &semaphore_create_info, nullptr, &semaphore); + + VkCommandPool command_pool; + VkCommandPoolCreateInfo pool_create_info{}; + pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + pool_create_info.queueFamilyIndex = m_device->graphics_queue_node_index_; + pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + vkCreateCommandPool(m_device->device(), &pool_create_info, nullptr, &command_pool); + + VkCommandBuffer command_buffer[2]; + VkCommandBufferAllocateInfo command_buffer_allocate_info{}; + command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + command_buffer_allocate_info.commandPool = command_pool; + command_buffer_allocate_info.commandBufferCount = 2; + command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + vkAllocateCommandBuffers(m_device->device(), &command_buffer_allocate_info, command_buffer); + + { + VkCommandBufferBeginInfo begin_info{}; + begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + vkBeginCommandBuffer(command_buffer[0], &begin_info); + + vkCmdPipelineBarrier(command_buffer[0], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, + nullptr, 0, nullptr, 0, nullptr); + + VkViewport viewport{}; + viewport.maxDepth = 1.0f; + viewport.minDepth = 0.0f; + viewport.width = 512; + viewport.height = 512; + viewport.x = 0; + viewport.y = 0; + vkCmdSetViewport(command_buffer[0], 0, 1, &viewport); + vkEndCommandBuffer(command_buffer[0]); + } + { + VkCommandBufferBeginInfo begin_info{}; + begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + vkBeginCommandBuffer(command_buffer[1], &begin_info); + + VkViewport viewport{}; + viewport.maxDepth = 1.0f; + viewport.minDepth = 0.0f; + viewport.width = 512; + viewport.height = 512; + viewport.x = 0; + viewport.y = 0; + vkCmdSetViewport(command_buffer[1], 0, 1, &viewport); + vkEndCommandBuffer(command_buffer[1]); + } + { + VkSubmitInfo submit_info[2]; + VkPipelineStageFlags flags[]{ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT }; + + submit_info[0].sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info[0].pNext = NULL; + submit_info[0].commandBufferCount = 1; + submit_info[0].pCommandBuffers = &command_buffer[0]; + submit_info[0].signalSemaphoreCount = 1; + submit_info[0].pSignalSemaphores = &semaphore; + submit_info[0].waitSemaphoreCount = 0; + submit_info[0].pWaitSemaphores = NULL; + submit_info[0].pWaitDstStageMask = 0; + + submit_info[1].sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info[1].pNext = NULL; + submit_info[1].commandBufferCount = 1; + submit_info[1].pCommandBuffers = &command_buffer[1]; + submit_info[1].waitSemaphoreCount = 1; + submit_info[1].pWaitSemaphores = &semaphore; + submit_info[1].pWaitDstStageMask = flags; + submit_info[1].signalSemaphoreCount = 0; + submit_info[1].pSignalSemaphores = NULL; + vkQueueSubmit(m_device->m_queue, 2, &submit_info[0], fence); + } + + vkWaitForFences(m_device->device(), 1, &fence, VK_TRUE, UINT64_MAX); + + vkDestroyFence(m_device->device(), fence, nullptr); + vkFreeCommandBuffers(m_device->device(), command_pool, 2, &command_buffer[0]); + vkDestroyCommandPool(m_device->device(), command_pool, NULL); + vkDestroySemaphore(m_device->device(), semaphore, nullptr); + + m_errorMonitor->VerifyNotFound(); +} + +TEST_F(VkPositiveLayerTest, RenderPassSecondaryCommandBuffersMultipleTimes) { + m_errorMonitor->ExpectSuccess(); + + ASSERT_NO_FATAL_FAILURE(InitState()); + ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); + + BeginCommandBuffer(); // Framework implicitly begins the renderpass. + vkCmdEndRenderPass(m_commandBuffer->GetBufferHandle()); // End implicit. + + vkCmdBeginRenderPass(m_commandBuffer->GetBufferHandle(), &m_renderPassBeginInfo, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); + vkCmdEndRenderPass(m_commandBuffer->GetBufferHandle()); + m_errorMonitor->VerifyNotFound(); + vkCmdBeginRenderPass(m_commandBuffer->GetBufferHandle(), &m_renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + m_errorMonitor->VerifyNotFound(); + vkCmdEndRenderPass(m_commandBuffer->GetBufferHandle()); + m_errorMonitor->VerifyNotFound(); + + m_commandBuffer->EndCommandBuffer(); + m_errorMonitor->VerifyNotFound(); +} + +TEST_F(VkPositiveLayerTest, ValidRenderPassAttachmentLayoutWithLoadOp) { + TEST_DESCRIPTION("Positive test where we create a renderpass with an " + "attachment that uses LOAD_OP_CLEAR, the first subpass " + "has a valid layout, and a second subpass then uses a " + "valid *READ_ONLY* layout."); + m_errorMonitor->ExpectSuccess(); + ASSERT_NO_FATAL_FAILURE(InitState()); + + VkAttachmentReference attach[2] = {}; + attach[0].attachment = 0; + attach[0].layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + attach[1].attachment = 0; + attach[1].layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; + VkSubpassDescription subpasses[2] = {}; + // First subpass clears DS attach on load + subpasses[0].pDepthStencilAttachment = &attach[0]; + // 2nd subpass reads in DS as input attachment + subpasses[1].inputAttachmentCount = 1; + subpasses[1].pInputAttachments = &attach[1]; + VkAttachmentDescription attach_desc = {}; + attach_desc.format = VK_FORMAT_D24_UNORM_S8_UINT; + attach_desc.samples = VK_SAMPLE_COUNT_1_BIT; + attach_desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attach_desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attach_desc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attach_desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attach_desc.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + attach_desc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; + VkRenderPassCreateInfo rpci = {}; + rpci.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + rpci.attachmentCount = 1; + rpci.pAttachments = &attach_desc; + rpci.subpassCount = 2; + rpci.pSubpasses = subpasses; + + // Now create RenderPass and verify no errors + VkRenderPass rp; + vkCreateRenderPass(m_device->device(), &rpci, NULL, &rp); + m_errorMonitor->VerifyNotFound(); + + vkDestroyRenderPass(m_device->device(), rp, NULL); +} + +TEST_F(VkPositiveLayerTest, CreatePipelineAttribMatrixType) { + TEST_DESCRIPTION("Test that pipeline validation accepts matrices passed " + "as vertex attributes"); + m_errorMonitor->ExpectSuccess(); + + ASSERT_NO_FATAL_FAILURE(InitState()); + ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); + + VkVertexInputBindingDescription input_binding; + memset(&input_binding, 0, sizeof(input_binding)); + + VkVertexInputAttributeDescription input_attribs[2]; + memset(input_attribs, 0, sizeof(input_attribs)); + + for (int i = 0; i < 2; i++) { + input_attribs[i].format = VK_FORMAT_R32G32B32A32_SFLOAT; + input_attribs[i].location = i; + } + + char const *vsSource = "#version 450\n" + "\n" + "layout(location=0) in mat2x4 x;\n" + "out gl_PerVertex {\n" + " vec4 gl_Position;\n" + "};\n" + "void main(){\n" + " gl_Position = x[0] + x[1];\n" + "}\n"; + char const *fsSource = "#version 450\n" + "\n" + "layout(location=0) out vec4 color;\n" + "void main(){\n" + " color = vec4(1);\n" + "}\n"; + + VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); + VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); + + VkPipelineObj pipe(m_device); + pipe.AddColorAttachment(); + pipe.AddShader(&vs); + pipe.AddShader(&fs); + + pipe.AddVertexInputBindings(&input_binding, 1); + pipe.AddVertexInputAttribs(input_attribs, 2); + + VkDescriptorSetObj descriptorSet(m_device); + descriptorSet.AppendDummy(); + descriptorSet.CreateVKDescriptorSet(m_commandBuffer); + + pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); + + /* expect success */ + m_errorMonitor->VerifyNotFound(); +} + +TEST_F(VkPositiveLayerTest, CreatePipelineAttribArrayType) { + m_errorMonitor->ExpectSuccess(); + + ASSERT_NO_FATAL_FAILURE(InitState()); + ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); + + VkVertexInputBindingDescription input_binding; + memset(&input_binding, 0, sizeof(input_binding)); + + VkVertexInputAttributeDescription input_attribs[2]; + memset(input_attribs, 0, sizeof(input_attribs)); + + for (int i = 0; i < 2; i++) { + input_attribs[i].format = VK_FORMAT_R32G32B32A32_SFLOAT; + input_attribs[i].location = i; + } + + char const *vsSource = "#version 450\n" + "\n" + "layout(location=0) in vec4 x[2];\n" + "out gl_PerVertex {\n" + " vec4 gl_Position;\n" + "};\n" + "void main(){\n" + " gl_Position = x[0] + x[1];\n" + "}\n"; + char const *fsSource = "#version 450\n" + "\n" + "layout(location=0) out vec4 color;\n" + "void main(){\n" + " color = vec4(1);\n" + "}\n"; + + VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); + VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); + + VkPipelineObj pipe(m_device); + pipe.AddColorAttachment(); + pipe.AddShader(&vs); + pipe.AddShader(&fs); + + pipe.AddVertexInputBindings(&input_binding, 1); + pipe.AddVertexInputAttribs(input_attribs, 2); + + VkDescriptorSetObj descriptorSet(m_device); + descriptorSet.AppendDummy(); + descriptorSet.CreateVKDescriptorSet(m_commandBuffer); + + pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); + + m_errorMonitor->VerifyNotFound(); +} + +TEST_F(VkPositiveLayerTest, CreatePipelineAttribComponents) { + TEST_DESCRIPTION("Test that pipeline validation accepts consuming a vertex attribute " + "through multiple vertex shader inputs, each consuming a different " + "subset of the components."); + m_errorMonitor->ExpectSuccess(); + + ASSERT_NO_FATAL_FAILURE(InitState()); + ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); + + VkVertexInputBindingDescription input_binding; + memset(&input_binding, 0, sizeof(input_binding)); + + VkVertexInputAttributeDescription input_attribs[3]; + memset(input_attribs, 0, sizeof(input_attribs)); + + for (int i = 0; i < 3; i++) { + input_attribs[i].format = VK_FORMAT_R32G32B32A32_SFLOAT; + input_attribs[i].location = i; + } + + char const *vsSource = "#version 450\n" + "\n" + "layout(location=0) in vec4 x;\n" + "layout(location=1) in vec3 y1;\n" + "layout(location=1, component=3) in float y2;\n" + "layout(location=2) in vec4 z;\n" + "out gl_PerVertex {\n" + " vec4 gl_Position;\n" + "};\n" + "void main(){\n" + " gl_Position = x + vec4(y1, y2) + z;\n" + "}\n"; + char const *fsSource = "#version 450\n" + "\n" + "layout(location=0) out vec4 color;\n" + "void main(){\n" + " color = vec4(1);\n" + "}\n"; + + VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); + VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); + + VkPipelineObj pipe(m_device); + pipe.AddColorAttachment(); + pipe.AddShader(&vs); + pipe.AddShader(&fs); + + pipe.AddVertexInputBindings(&input_binding, 1); + pipe.AddVertexInputAttribs(input_attribs, 3); + + VkDescriptorSetObj descriptorSet(m_device); + descriptorSet.AppendDummy(); + descriptorSet.CreateVKDescriptorSet(m_commandBuffer); + + pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); + + m_errorMonitor->VerifyNotFound(); +} + +TEST_F(VkPositiveLayerTest, CreatePipelineSimplePositive) { + m_errorMonitor->ExpectSuccess(); + + ASSERT_NO_FATAL_FAILURE(InitState()); + ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); + + char const *vsSource = "#version 450\n" + "out gl_PerVertex {\n" + " vec4 gl_Position;\n" + "};\n" + "void main(){\n" + " gl_Position = vec4(0);\n" + "}\n"; + char const *fsSource = "#version 450\n" + "\n" + "layout(location=0) out vec4 color;\n" + "void main(){\n" + " color = vec4(1);\n" + "}\n"; + + VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); + VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); + + VkPipelineObj pipe(m_device); + pipe.AddColorAttachment(); + pipe.AddShader(&vs); + pipe.AddShader(&fs); + + VkDescriptorSetObj descriptorSet(m_device); + descriptorSet.AppendDummy(); + descriptorSet.CreateVKDescriptorSet(m_commandBuffer); + + pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); + + m_errorMonitor->VerifyNotFound(); +} + +TEST_F(VkPositiveLayerTest, CreatePipelineRelaxedTypeMatch) { + TEST_DESCRIPTION("Test that pipeline validation accepts the relaxed type matching rules " + "set out in 14.1.3: fundamental type must match, and producer side must " + "have at least as many components"); + m_errorMonitor->ExpectSuccess(); + + // VK 1.0.8 Specification, 14.1.3 "Additionally,..." block + + ASSERT_NO_FATAL_FAILURE(InitState()); + ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); + + char const *vsSource = "#version 450\n" + "out gl_PerVertex {\n" + " vec4 gl_Position;\n" + "};\n" + "layout(location=0) out vec3 x;\n" + "layout(location=1) out ivec3 y;\n" + "layout(location=2) out vec3 z;\n" + "void main(){\n" + " gl_Position = vec4(0);\n" + " x = vec3(0); y = ivec3(0); z = vec3(0);\n" + "}\n"; + char const *fsSource = "#version 450\n" + "\n" + "layout(location=0) out vec4 color;\n" + "layout(location=0) in float x;\n" + "layout(location=1) flat in int y;\n" + "layout(location=2) in vec2 z;\n" + "void main(){\n" + " color = vec4(1 + x + y + z.x);\n" + "}\n"; + + VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); + VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); + + VkPipelineObj pipe(m_device); + pipe.AddColorAttachment(); + pipe.AddShader(&vs); + pipe.AddShader(&fs); + + VkDescriptorSetObj descriptorSet(m_device); + descriptorSet.AppendDummy(); + descriptorSet.CreateVKDescriptorSet(m_commandBuffer); + + VkResult err = VK_SUCCESS; + err = pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); + ASSERT_VK_SUCCESS(err); + + m_errorMonitor->VerifyNotFound(); +} + +TEST_F(VkPositiveLayerTest, CreatePipelineTessPerVertex) { + TEST_DESCRIPTION("Test that pipeline validation accepts per-vertex variables " + "passed between the TCS and TES stages"); + m_errorMonitor->ExpectSuccess(); + + ASSERT_NO_FATAL_FAILURE(InitState()); + ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); + + if (!m_device->phy().features().tessellationShader) { + printf("Device does not support tessellation shaders; skipped.\n"); + return; + } + + char const *vsSource = "#version 450\n" + "void main(){}\n"; + char const *tcsSource = "#version 450\n" + "layout(location=0) out int x[];\n" + "layout(vertices=3) out;\n" + "void main(){\n" + " gl_TessLevelOuter[0] = gl_TessLevelOuter[1] = gl_TessLevelOuter[2] = 1;\n" + " gl_TessLevelInner[0] = 1;\n" + " x[gl_InvocationID] = gl_InvocationID;\n" + "}\n"; + char const *tesSource = "#version 450\n" + "layout(triangles, equal_spacing, cw) in;\n" + "layout(location=0) in int x[];\n" + "out gl_PerVertex { vec4 gl_Position; };\n" + "void main(){\n" + " gl_Position.xyz = gl_TessCoord;\n" + " gl_Position.w = x[0] + x[1] + x[2];\n" + "}\n"; + char const *fsSource = "#version 450\n" + "layout(location=0) out vec4 color;\n" + "void main(){\n" + " color = vec4(1);\n" + "}\n"; + + VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); + VkShaderObj tcs(m_device, tcsSource, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, this); + VkShaderObj tes(m_device, tesSource, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, this); + VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); + + VkPipelineInputAssemblyStateCreateInfo iasci{ VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, nullptr, 0, + VK_PRIMITIVE_TOPOLOGY_PATCH_LIST, VK_FALSE }; + + VkPipelineTessellationStateCreateInfo tsci{ VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO, nullptr, 0, 3 }; + + VkPipelineObj pipe(m_device); + pipe.SetInputAssembly(&iasci); + pipe.SetTessellation(&tsci); + pipe.AddColorAttachment(); + pipe.AddShader(&vs); + pipe.AddShader(&tcs); + pipe.AddShader(&tes); + pipe.AddShader(&fs); + + VkDescriptorSetObj descriptorSet(m_device); + descriptorSet.AppendDummy(); + descriptorSet.CreateVKDescriptorSet(m_commandBuffer); + + pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); + + m_errorMonitor->VerifyNotFound(); +} + +TEST_F(VkPositiveLayerTest, CreatePipelineGeometryInputBlockPositive) { + TEST_DESCRIPTION("Test that pipeline validation accepts a user-defined " + "interface block passed into the geometry shader. This " + "is interesting because the 'extra' array level is not " + "present on the member type, but on the block instance."); + m_errorMonitor->ExpectSuccess(); + + ASSERT_NO_FATAL_FAILURE(InitState()); + ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); + + if (!m_device->phy().features().geometryShader) { + printf("Device does not support geometry shaders; skipped.\n"); + return; + } + + char const *vsSource = "#version 450\n" + "layout(location=0) out VertexData { vec4 x; } vs_out;\n" + "void main(){\n" + " vs_out.x = vec4(1);\n" + "}\n"; + char const *gsSource = "#version 450\n" + "layout(triangles) in;\n" + "layout(triangle_strip, max_vertices=3) out;\n" + "layout(location=0) in VertexData { vec4 x; } gs_in[];\n" + "out gl_PerVertex { vec4 gl_Position; };\n" + "void main() {\n" + " gl_Position = gs_in[0].x;\n" + " EmitVertex();\n" + "}\n"; + char const *fsSource = "#version 450\n" + "layout(location=0) out vec4 color;\n" + "void main(){\n" + " color = vec4(1);\n" + "}\n"; + + VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); + VkShaderObj gs(m_device, gsSource, VK_SHADER_STAGE_GEOMETRY_BIT, this); + VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); + + VkPipelineObj pipe(m_device); + pipe.AddColorAttachment(); + pipe.AddShader(&vs); + pipe.AddShader(&gs); + pipe.AddShader(&fs); + + VkDescriptorSetObj descriptorSet(m_device); + descriptorSet.AppendDummy(); + descriptorSet.CreateVKDescriptorSet(m_commandBuffer); + + pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); + + m_errorMonitor->VerifyNotFound(); +} + +TEST_F(VkPositiveLayerTest, CreatePipeline64BitAttributesPositive) { + TEST_DESCRIPTION("Test that pipeline validation accepts basic use of 64bit vertex " + "attributes. This is interesting because they consume multiple " + "locations."); + m_errorMonitor->ExpectSuccess(); + + ASSERT_NO_FATAL_FAILURE(InitState()); + ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); + + if (!m_device->phy().features().shaderFloat64) { + printf("Device does not support 64bit vertex attributes; skipped.\n"); + return; + } + + VkVertexInputBindingDescription input_bindings[1]; + memset(input_bindings, 0, sizeof(input_bindings)); + + VkVertexInputAttributeDescription input_attribs[4]; + memset(input_attribs, 0, sizeof(input_attribs)); + input_attribs[0].location = 0; + input_attribs[0].offset = 0; + input_attribs[0].format = VK_FORMAT_R64G64B64A64_SFLOAT; + input_attribs[1].location = 2; + input_attribs[1].offset = 32; + input_attribs[1].format = VK_FORMAT_R64G64B64A64_SFLOAT; + input_attribs[2].location = 4; + input_attribs[2].offset = 64; + input_attribs[2].format = VK_FORMAT_R64G64B64A64_SFLOAT; + input_attribs[3].location = 6; + input_attribs[3].offset = 96; + input_attribs[3].format = VK_FORMAT_R64G64B64A64_SFLOAT; + + char const *vsSource = "#version 450\n" + "\n" + "layout(location=0) in dmat4 x;\n" + "out gl_PerVertex {\n" + " vec4 gl_Position;\n" + "};\n" + "void main(){\n" + " gl_Position = vec4(x[0][0]);\n" + "}\n"; + char const *fsSource = "#version 450\n" + "\n" + "layout(location=0) out vec4 color;\n" + "void main(){\n" + " color = vec4(1);\n" + "}\n"; + + VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); + VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); + + VkPipelineObj pipe(m_device); + pipe.AddColorAttachment(); + pipe.AddShader(&vs); + pipe.AddShader(&fs); + + pipe.AddVertexInputBindings(input_bindings, 1); + pipe.AddVertexInputAttribs(input_attribs, 4); + + VkDescriptorSetObj descriptorSet(m_device); + descriptorSet.AppendDummy(); + descriptorSet.CreateVKDescriptorSet(m_commandBuffer); + + pipe.CreateVKPipeline(descriptorSet.GetPipelineLayout(), renderPass()); + + m_errorMonitor->VerifyNotFound(); +} + +TEST_F(VkPositiveLayerTest, CreatePipelineInputAttachmentPositive) { + TEST_DESCRIPTION("Positive test for a correctly matched input attachment"); + m_errorMonitor->ExpectSuccess(); + + ASSERT_NO_FATAL_FAILURE(InitState()); + + char const *vsSource = "#version 450\n" + "\n" + "out gl_PerVertex {\n" + " vec4 gl_Position;\n" + "};\n" + "void main(){\n" + " gl_Position = vec4(1);\n" + "}\n"; + char const *fsSource = "#version 450\n" + "\n" + "layout(input_attachment_index=0, set=0, binding=0) uniform subpassInput x;\n" + "layout(location=0) out vec4 color;\n" + "void main() {\n" + " color = subpassLoad(x);\n" + "}\n"; + + VkShaderObj vs(m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT, this); + VkShaderObj fs(m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, this); + + VkPipelineObj pipe(m_device); + pipe.AddShader(&vs); + pipe.AddShader(&fs); + pipe.AddColorAttachment(); + ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); + + VkDescriptorSetLayoutBinding dslb = { 0, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr }; + VkDescriptorSetLayoutCreateInfo dslci = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, nullptr, 0, 1, &dslb }; + VkDescriptorSetLayout dsl; + VkResult err = vkCreateDescriptorSetLayout(m_device->device(), &dslci, nullptr, &dsl); + ASSERT_VK_SUCCESS(err); + + VkPipelineLayoutCreateInfo plci = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, nullptr, 0, 1, &dsl, 0, nullptr }; + VkPipelineLayout pl; + err = vkCreatePipelineLayout(m_device->device(), &plci, nullptr, &pl); + ASSERT_VK_SUCCESS(err); + + VkAttachmentDescription descs[2] = { + { 0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, + VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }, + { 0, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, + VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL }, + }; + VkAttachmentReference color = { + 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + }; + VkAttachmentReference input = { + 1, VK_IMAGE_LAYOUT_GENERAL, + }; + + VkSubpassDescription sd = { 0, VK_PIPELINE_BIND_POINT_GRAPHICS, 1, &input, 1, &color, nullptr, nullptr, 0, nullptr }; + + VkRenderPassCreateInfo rpci = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, nullptr, 0, 2, descs, 1, &sd, 0, nullptr }; + VkRenderPass rp; + err = vkCreateRenderPass(m_device->device(), &rpci, nullptr, &rp); + ASSERT_VK_SUCCESS(err); + + // should be OK. would go wrong here if it's going to... + pipe.CreateVKPipeline(pl, rp); + + m_errorMonitor->VerifyNotFound(); + + vkDestroyRenderPass(m_device->device(), rp, nullptr); + vkDestroyPipelineLayout(m_device->device(), pl, nullptr); + vkDestroyDescriptorSetLayout(m_device->device(), dsl, nullptr); +} + +TEST_F(VkPositiveLayerTest, CreateComputePipelineMissingDescriptorUnusedPositive) { + TEST_DESCRIPTION("Test that pipeline validation accepts a compute pipeline which declares a " + "descriptor-backed resource which is not provided, but the shader does not " + "statically use it. This is interesting because it requires compute pipelines " + "to have a proper descriptor use walk, which they didn't for some time."); + m_errorMonitor->ExpectSuccess(); + + ASSERT_NO_FATAL_FAILURE(InitState()); + + char const *csSource = "#version 450\n" + "\n" + "layout(local_size_x=1) in;\n" + "layout(set=0, binding=0) buffer block { vec4 x; };\n" + "void main(){\n" + " // x is not used.\n" + "}\n"; + + VkShaderObj cs(m_device, csSource, VK_SHADER_STAGE_COMPUTE_BIT, this); + + VkDescriptorSetObj descriptorSet(m_device); + descriptorSet.CreateVKDescriptorSet(m_commandBuffer); + + VkComputePipelineCreateInfo cpci = { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, + nullptr, + 0, + { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, nullptr, 0, + VK_SHADER_STAGE_COMPUTE_BIT, cs.handle(), "main", nullptr }, + descriptorSet.GetPipelineLayout(), + VK_NULL_HANDLE, + -1 }; + + VkPipeline pipe; + VkResult err = vkCreateComputePipelines(m_device->device(), VK_NULL_HANDLE, 1, &cpci, nullptr, &pipe); + + m_errorMonitor->VerifyNotFound(); + + if (err == VK_SUCCESS) { + vkDestroyPipeline(m_device->device(), pipe, nullptr); + } +} + +TEST_F(VkPositiveLayerTest, CreateComputePipelineCombinedImageSamplerConsumedAsSampler) { + TEST_DESCRIPTION("Test that pipeline validation accepts a shader consuming only the " + "sampler portion of a combined image + sampler"); + m_errorMonitor->ExpectSuccess(); + + ASSERT_NO_FATAL_FAILURE(InitState()); + + VkDescriptorSetLayoutBinding bindings[] = { + { 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr }, + { 1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr }, + { 2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr }, + }; + VkDescriptorSetLayoutCreateInfo dslci = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, nullptr, 0, 3, bindings }; + VkDescriptorSetLayout dsl; + VkResult err = vkCreateDescriptorSetLayout(m_device->device(), &dslci, nullptr, &dsl); + ASSERT_VK_SUCCESS(err); + + VkPipelineLayoutCreateInfo plci = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, nullptr, 0, 1, &dsl, 0, nullptr }; + VkPipelineLayout pl; + err = vkCreatePipelineLayout(m_device->device(), &plci, nullptr, &pl); + ASSERT_VK_SUCCESS(err); + + char const *csSource = "#version 450\n" + "\n" + "layout(local_size_x=1) in;\n" + "layout(set=0, binding=0) uniform sampler s;\n" + "layout(set=0, binding=1) uniform texture2D t;\n" + "layout(set=0, binding=2) buffer block { vec4 x; };\n" + "void main() {\n" + " x = texture(sampler2D(t, s), vec2(0));\n" + "}\n"; + VkShaderObj cs(m_device, csSource, VK_SHADER_STAGE_COMPUTE_BIT, this); + + VkComputePipelineCreateInfo cpci = { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, + nullptr, + 0, + { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, nullptr, 0, + VK_SHADER_STAGE_COMPUTE_BIT, cs.handle(), "main", nullptr }, + pl, + VK_NULL_HANDLE, + -1 }; + + VkPipeline pipe; + err = vkCreateComputePipelines(m_device->device(), VK_NULL_HANDLE, 1, &cpci, nullptr, &pipe); + + m_errorMonitor->VerifyNotFound(); + + if (err == VK_SUCCESS) { + vkDestroyPipeline(m_device->device(), pipe, nullptr); + } + + vkDestroyPipelineLayout(m_device->device(), pl, nullptr); + vkDestroyDescriptorSetLayout(m_device->device(), dsl, nullptr); +} + +TEST_F(VkPositiveLayerTest, CreateComputePipelineCombinedImageSamplerConsumedAsImage) { + TEST_DESCRIPTION("Test that pipeline validation accepts a shader consuming only the " + "image portion of a combined image + sampler"); + m_errorMonitor->ExpectSuccess(); + + ASSERT_NO_FATAL_FAILURE(InitState()); + + VkDescriptorSetLayoutBinding bindings[] = { + { 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr }, + { 1, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr }, + { 2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr }, + }; + VkDescriptorSetLayoutCreateInfo dslci = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, nullptr, 0, 3, bindings }; + VkDescriptorSetLayout dsl; + VkResult err = vkCreateDescriptorSetLayout(m_device->device(), &dslci, nullptr, &dsl); + ASSERT_VK_SUCCESS(err); + + VkPipelineLayoutCreateInfo plci = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, nullptr, 0, 1, &dsl, 0, nullptr }; + VkPipelineLayout pl; + err = vkCreatePipelineLayout(m_device->device(), &plci, nullptr, &pl); + ASSERT_VK_SUCCESS(err); + + char const *csSource = "#version 450\n" + "\n" + "layout(local_size_x=1) in;\n" + "layout(set=0, binding=0) uniform texture2D t;\n" + "layout(set=0, binding=1) uniform sampler s;\n" + "layout(set=0, binding=2) buffer block { vec4 x; };\n" + "void main() {\n" + " x = texture(sampler2D(t, s), vec2(0));\n" + "}\n"; + VkShaderObj cs(m_device, csSource, VK_SHADER_STAGE_COMPUTE_BIT, this); + + VkComputePipelineCreateInfo cpci = { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, + nullptr, + 0, + { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, nullptr, 0, + VK_SHADER_STAGE_COMPUTE_BIT, cs.handle(), "main", nullptr }, + pl, + VK_NULL_HANDLE, + -1 }; + + VkPipeline pipe; + err = vkCreateComputePipelines(m_device->device(), VK_NULL_HANDLE, 1, &cpci, nullptr, &pipe); + + m_errorMonitor->VerifyNotFound(); + + if (err == VK_SUCCESS) { + vkDestroyPipeline(m_device->device(), pipe, nullptr); + } + + vkDestroyPipelineLayout(m_device->device(), pl, nullptr); + vkDestroyDescriptorSetLayout(m_device->device(), dsl, nullptr); +} + +TEST_F(VkPositiveLayerTest, CreateComputePipelineCombinedImageSamplerConsumedAsBoth) { + TEST_DESCRIPTION("Test that pipeline validation accepts a shader consuming " + "both the sampler and the image of a combined image+sampler " + "but via separate variables"); + m_errorMonitor->ExpectSuccess(); + + ASSERT_NO_FATAL_FAILURE(InitState()); + + VkDescriptorSetLayoutBinding bindings[] = { + { 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr }, + { 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr }, + }; + VkDescriptorSetLayoutCreateInfo dslci = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, nullptr, 0, 2, bindings }; + VkDescriptorSetLayout dsl; + VkResult err = vkCreateDescriptorSetLayout(m_device->device(), &dslci, nullptr, &dsl); + ASSERT_VK_SUCCESS(err); + + VkPipelineLayoutCreateInfo plci = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, nullptr, 0, 1, &dsl, 0, nullptr }; + VkPipelineLayout pl; + err = vkCreatePipelineLayout(m_device->device(), &plci, nullptr, &pl); + ASSERT_VK_SUCCESS(err); + + char const *csSource = "#version 450\n" + "\n" + "layout(local_size_x=1) in;\n" + "layout(set=0, binding=0) uniform texture2D t;\n" + "layout(set=0, binding=0) uniform sampler s; // both binding 0!\n" + "layout(set=0, binding=1) buffer block { vec4 x; };\n" + "void main() {\n" + " x = texture(sampler2D(t, s), vec2(0));\n" + "}\n"; + VkShaderObj cs(m_device, csSource, VK_SHADER_STAGE_COMPUTE_BIT, this); + + VkComputePipelineCreateInfo cpci = { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, + nullptr, + 0, + { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, nullptr, 0, + VK_SHADER_STAGE_COMPUTE_BIT, cs.handle(), "main", nullptr }, + pl, + VK_NULL_HANDLE, + -1 }; + + VkPipeline pipe; + err = vkCreateComputePipelines(m_device->device(), VK_NULL_HANDLE, 1, &cpci, nullptr, &pipe); + + m_errorMonitor->VerifyNotFound(); + + if (err == VK_SUCCESS) { + vkDestroyPipeline(m_device->device(), pipe, nullptr); + } + + vkDestroyPipelineLayout(m_device->device(), pl, nullptr); + vkDestroyDescriptorSetLayout(m_device->device(), dsl, nullptr); +} + +TEST_F(VkPositiveLayerTest, ValidStructPNext) { + TEST_DESCRIPTION("Verify that a valid pNext value is handled correctly"); + + ASSERT_NO_FATAL_FAILURE(InitState()); + + // Positive test to check parameter_validation and unique_objects support + // for NV_dedicated_allocation + uint32_t extension_count = 0; + bool supports_nv_dedicated_allocation = false; + VkResult err = vkEnumerateDeviceExtensionProperties(gpu(), nullptr, &extension_count, nullptr); + ASSERT_VK_SUCCESS(err); + + if (extension_count > 0) { + std::vector<VkExtensionProperties> available_extensions(extension_count); + + err = vkEnumerateDeviceExtensionProperties(gpu(), nullptr, &extension_count, &available_extensions[0]); + ASSERT_VK_SUCCESS(err); + + for (const auto &extension_props : available_extensions) { + if (strcmp(extension_props.extensionName, VK_NV_DEDICATED_ALLOCATION_EXTENSION_NAME) == 0) { + supports_nv_dedicated_allocation = true; + } + } + } + + if (supports_nv_dedicated_allocation) { + m_errorMonitor->ExpectSuccess(); + + VkDedicatedAllocationBufferCreateInfoNV dedicated_buffer_create_info = {}; + dedicated_buffer_create_info.sType = VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV; + dedicated_buffer_create_info.pNext = nullptr; + dedicated_buffer_create_info.dedicatedAllocation = VK_TRUE; + + uint32_t queue_family_index = 0; + VkBufferCreateInfo buffer_create_info = {}; + buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buffer_create_info.pNext = &dedicated_buffer_create_info; + buffer_create_info.size = 1024; + buffer_create_info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + buffer_create_info.queueFamilyIndexCount = 1; + buffer_create_info.pQueueFamilyIndices = &queue_family_index; + + VkBuffer buffer; + VkResult err = vkCreateBuffer(m_device->device(), &buffer_create_info, NULL, &buffer); + ASSERT_VK_SUCCESS(err); + + VkMemoryRequirements memory_reqs; + vkGetBufferMemoryRequirements(m_device->device(), buffer, &memory_reqs); + + VkDedicatedAllocationMemoryAllocateInfoNV dedicated_memory_info = {}; + dedicated_memory_info.sType = VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV; + dedicated_memory_info.pNext = nullptr; + dedicated_memory_info.buffer = buffer; + dedicated_memory_info.image = VK_NULL_HANDLE; + + VkMemoryAllocateInfo memory_info = {}; + memory_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + memory_info.pNext = &dedicated_memory_info; + memory_info.allocationSize = memory_reqs.size; + + bool pass; + pass = m_device->phy().set_memory_type(memory_reqs.memoryTypeBits, &memory_info, 0); + ASSERT_TRUE(pass); + + VkDeviceMemory buffer_memory; + err = vkAllocateMemory(m_device->device(), &memory_info, NULL, &buffer_memory); + ASSERT_VK_SUCCESS(err); + + err = vkBindBufferMemory(m_device->device(), buffer, buffer_memory, 0); + ASSERT_VK_SUCCESS(err); + + vkDestroyBuffer(m_device->device(), buffer, NULL); + vkFreeMemory(m_device->device(), buffer_memory, NULL); + + m_errorMonitor->VerifyNotFound(); + } +} + +TEST_F(VkPositiveLayerTest, PSOPolygonModeValid) { + VkResult err; + + TEST_DESCRIPTION("Verify that using a solid polygon fill mode works correctly."); + + ASSERT_NO_FATAL_FAILURE(InitState()); + ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); + + std::vector<const char *> device_extension_names; + auto features = m_device->phy().features(); + // Artificially disable support for non-solid fill modes + features.fillModeNonSolid = false; + // The sacrificial device object + VkDeviceObj test_device(0, gpu(), device_extension_names, &features); + + VkRenderpassObj render_pass(&test_device); + + VkPipelineLayoutCreateInfo pipeline_layout_ci = {}; + pipeline_layout_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipeline_layout_ci.setLayoutCount = 0; + pipeline_layout_ci.pSetLayouts = NULL; + + VkPipelineLayout pipeline_layout; + err = vkCreatePipelineLayout(test_device.device(), &pipeline_layout_ci, NULL, &pipeline_layout); + ASSERT_VK_SUCCESS(err); + + VkPipelineRasterizationStateCreateInfo rs_ci = {}; + rs_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rs_ci.pNext = nullptr; + rs_ci.lineWidth = 1.0f; + rs_ci.rasterizerDiscardEnable = true; + + VkShaderObj vs(&test_device, bindStateVertShaderText, VK_SHADER_STAGE_VERTEX_BIT, this); + VkShaderObj fs(&test_device, bindStateFragShaderText, VK_SHADER_STAGE_FRAGMENT_BIT, this); + + // Set polygonMode=FILL. No error is expected + m_errorMonitor->ExpectSuccess(); + { + VkPipelineObj pipe(&test_device); + pipe.AddShader(&vs); + pipe.AddShader(&fs); + pipe.AddColorAttachment(); + // Set polygonMode to a good value + rs_ci.polygonMode = VK_POLYGON_MODE_FILL; + pipe.SetRasterization(&rs_ci); + pipe.CreateVKPipeline(pipeline_layout, render_pass.handle()); + } + m_errorMonitor->VerifyNotFound(); + + vkDestroyPipelineLayout(test_device.device(), pipeline_layout, NULL); +} + +TEST_F(VkPositiveLayerTest, ValidPushConstants) { + VkResult err; + ASSERT_NO_FATAL_FAILURE(InitState()); + ASSERT_NO_FATAL_FAILURE(InitViewport()); + ASSERT_NO_FATAL_FAILURE(InitRenderTarget()); + + VkPipelineLayout pipeline_layout; + VkPushConstantRange pc_range = {}; + VkPipelineLayoutCreateInfo pipeline_layout_ci = {}; + pipeline_layout_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipeline_layout_ci.pushConstantRangeCount = 1; + pipeline_layout_ci.pPushConstantRanges = &pc_range; + + // + // Check for invalid push constant ranges in pipeline layouts. + // + struct PipelineLayoutTestCase { + VkPushConstantRange const range; + char const *msg; + }; + + // Check for overlapping ranges + const uint32_t ranges_per_test = 5; + struct OverlappingRangeTestCase { + VkPushConstantRange const ranges[ranges_per_test]; + char const *msg; + }; + + // Run some positive tests to make sure overlap checking in the layer is OK + const std::array<OverlappingRangeTestCase, 2> overlapping_range_tests_pos = { { { { { VK_SHADER_STAGE_VERTEX_BIT, 0, 4 }, + { VK_SHADER_STAGE_VERTEX_BIT, 4, 4 }, + { VK_SHADER_STAGE_VERTEX_BIT, 8, 4 }, + { VK_SHADER_STAGE_VERTEX_BIT, 12, 4 }, + { VK_SHADER_STAGE_VERTEX_BIT, 16, 4 } }, + "" }, + { { { VK_SHADER_STAGE_VERTEX_BIT, 92, 24 }, + { VK_SHADER_STAGE_VERTEX_BIT, 80, 4 }, + { VK_SHADER_STAGE_VERTEX_BIT, 64, 8 }, + { VK_SHADER_STAGE_VERTEX_BIT, 4, 16 }, + { VK_SHADER_STAGE_VERTEX_BIT, 0, 4 } }, + "" } } }; + for (const auto &iter : overlapping_range_tests_pos) { + pipeline_layout_ci.pPushConstantRanges = iter.ranges; + m_errorMonitor->ExpectSuccess(); + err = vkCreatePipelineLayout(m_device->device(), &pipeline_layout_ci, NULL, &pipeline_layout); + m_errorMonitor->VerifyNotFound(); + if (VK_SUCCESS == err) { + vkDestroyPipelineLayout(m_device->device(), pipeline_layout, NULL); + } + } + + // + // CmdPushConstants tests + // + const uint8_t dummy_values[100] = {}; + + BeginCommandBuffer(); + + // positive overlapping range tests with cmd + const std::array<PipelineLayoutTestCase, 4> cmd_overlap_tests_pos = { { + { { VK_SHADER_STAGE_VERTEX_BIT, 0, 16 }, "" }, + { { VK_SHADER_STAGE_VERTEX_BIT, 0, 4 }, "" }, + { { VK_SHADER_STAGE_VERTEX_BIT, 20, 12 }, "" }, + { { VK_SHADER_STAGE_VERTEX_BIT, 56, 36 }, "" }, + } }; + + // Setup ranges: [0,16) [20,36) [36,44) [44,52) [56,80) [80,92) + const VkPushConstantRange pc_range4[] = { + { VK_SHADER_STAGE_VERTEX_BIT, 20, 16 },{ VK_SHADER_STAGE_VERTEX_BIT, 0, 16 },{ VK_SHADER_STAGE_VERTEX_BIT, 44, 8 }, + { VK_SHADER_STAGE_VERTEX_BIT, 80, 12 },{ VK_SHADER_STAGE_VERTEX_BIT, 36, 8 },{ VK_SHADER_STAGE_VERTEX_BIT, 56, 24 }, + }; + + pipeline_layout_ci.pushConstantRangeCount = sizeof(pc_range4) / sizeof(VkPushConstantRange); + pipeline_layout_ci.pPushConstantRanges = pc_range4; + err = vkCreatePipelineLayout(m_device->device(), &pipeline_layout_ci, NULL, &pipeline_layout); + ASSERT_VK_SUCCESS(err); + for (const auto &iter : cmd_overlap_tests_pos) { + m_errorMonitor->ExpectSuccess(); + vkCmdPushConstants(m_commandBuffer->GetBufferHandle(), pipeline_layout, iter.range.stageFlags, iter.range.offset, + iter.range.size, dummy_values); + m_errorMonitor->VerifyNotFound(); + } + vkDestroyPipelineLayout(m_device->device(), pipeline_layout, NULL); + + EndCommandBuffer(); +} + + + + + + + +#if 0 // A few devices have issues with this test so disabling for now +TEST_F(VkPositiveLayerTest, LongFenceChain) +{ + m_errorMonitor->ExpectSuccess(); + + ASSERT_NO_FATAL_FAILURE(InitState()); + VkResult err; + + std::vector<VkFence> fences; + + const int chainLength = 32768; + + for (int i = 0; i < chainLength; i++) { + VkFenceCreateInfo fci = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr, 0 }; + VkFence fence; + err = vkCreateFence(m_device->device(), &fci, nullptr, &fence); + ASSERT_VK_SUCCESS(err); + + fences.push_back(fence); + + VkSubmitInfo si = { VK_STRUCTURE_TYPE_SUBMIT_INFO, nullptr, 0, nullptr, nullptr, + 0, nullptr, 0, nullptr }; + err = vkQueueSubmit(m_device->m_queue, 1, &si, fence); + ASSERT_VK_SUCCESS(err); + + } + + // BOOM, stack overflow. + vkWaitForFences(m_device->device(), 1, &fences.back(), VK_TRUE, UINT64_MAX); + + for (auto fence : fences) + vkDestroyFence(m_device->device(), fence, nullptr); + + m_errorMonitor->VerifyNotFound(); +} +#endif + + #if defined(ANDROID) && defined(VALIDATION_APK) static bool initialized = false; static bool active = false; |